s4:provision Simplify the module list
[Samba/ekacnet.git] / source4 / scripting / python / samba / provisionbackend.py
blob595c1bebbb3d7c235fc52141a0be79266a20ad46
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
29 import ldb
30 import os
31 import sys
32 import uuid
33 import time
34 import shutil
35 import subprocess
37 from samba import read_and_sub_file
38 from samba import Ldb
39 import urllib
40 from ldb import SCOPE_BASE, SCOPE_ONELEVEL, LdbError, timestring
41 from credentials import Credentials, DONT_USE_KERBEROS
42 from samba import setup_file
43 from schema import Schema
45 def setup_db_config(setup_path, dbdir):
46 """Setup a Berkeley database.
48 :param setup_path: Setup path function.
49 :param dbdir: Database directory."""
50 if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
51 os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
52 if not os.path.isdir(os.path.join(dbdir, "tmp")):
53 os.makedirs(os.path.join(dbdir, "tmp"), 0700)
55 setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"),
56 {"LDAPDBDIR": dbdir})
58 class ProvisionBackend(object):
59 def __init__(self, backend_type, paths=None, setup_path=None, lp=None, credentials=None,
60 names=None, message=None):
61 """Provision a backend for samba4"""
62 self.paths = paths
63 self.setup_path = setup_path
64 self.lp = lp
65 self.credentials = credentials
66 self.names = names
67 self.message = message
69 self.type = backend_type
71 # Set a default - the code for "existing" below replaces this
72 self.ldap_backend_type = backend_type
74 def init(self):
75 pass
77 def start(self):
78 pass
80 def shutdown(self):
81 pass
83 def post_setup(self):
84 pass
87 class LDBBackend(ProvisionBackend):
88 def __init__(self, backend_type, paths=None, setup_path=None, lp=None, credentials=None,
89 names=None, message=None):
91 super(LDBBackend, self).__init__(
92 backend_type=backend_type,
93 paths=paths, setup_path=setup_path,
94 lp=lp, credentials=credentials,
95 names=names,
96 message=message)
98 def init(self):
99 self.credentials = None
100 self.secrets_credentials = None
102 # Wipe the old sam.ldb databases away
103 shutil.rmtree(self.paths.samdb + ".d", True)
106 class ExistingBackend(ProvisionBackend):
107 def __init__(self, backend_type, paths=None, setup_path=None, lp=None, credentials=None,
108 names=None, message=None):
110 super(ExistingBackend, self).__init__(
111 backend_type=backend_type,
112 paths=paths, setup_path=setup_path,
113 lp=lp, credentials=credentials,
114 names=names,
115 message=message)
117 self.ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.ldapdir, "ldapi"), safe="")
119 def init(self):
120 #Check to see that this 'existing' LDAP backend in fact exists
121 ldapi_db = Ldb(self.ldapi_uri, credentials=self.credentials)
122 search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
123 expression="(objectClass=OpenLDAProotDSE)")
125 # If we have got here, then we must have a valid connection to the LDAP server, with valid credentials supplied
126 # This caused them to be set into the long-term database later in the script.
127 self.secrets_credentials = self.credentials
129 self.ldap_backend_type = "openldap" #For now, assume existing backends at least emulate OpenLDAP
132 class LDAPBackend(ProvisionBackend):
133 def __init__(self, backend_type, paths=None, setup_path=None, lp=None, credentials=None,
134 names=None, message=None,
135 domainsid=None,
136 schema=None,
137 hostname=None,
138 ldapadminpass=None,
139 slapd_path=None,
140 ldap_backend_extra_port=None,
141 ldap_dryrun_mode=False):
143 super(LDAPBackend, self).__init__(
144 backend_type=backend_type,
145 paths=paths, setup_path=setup_path,
146 lp=lp, credentials=credentials,
147 names=names,
148 message=message)
150 self.domainsid = domainsid
151 self.schema = schema
152 self.hostname = hostname
153 self.ldapadminpass = ldapadminpass
155 self.slapd_path = slapd_path
156 self.slapd_command = None
157 self.slapd_command_escaped = None
159 self.ldap_backend_extra_port = ldap_backend_extra_port
160 self.ldap_dryrun_mode = ldap_dryrun_mode
162 self.ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.ldapdir, "ldapi"), safe="")
164 if not os.path.exists(self.paths.ldapdir):
165 os.mkdir(self.paths.ldapdir)
167 def init(self):
168 # we will shortly start slapd with ldapi for final provisioning. first check with ldapsearch -> rootDSE via self.ldapi_uri
169 # if another instance of slapd is already running
170 try:
171 ldapi_db = Ldb(self.ldapi_uri)
172 search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
173 expression="(objectClass=OpenLDAProotDSE)");
174 try:
175 f = open(self.paths.slapdpid, "r")
176 p = f.read()
177 f.close()
178 self.message("Check for slapd Process with PID: " + str(p) + " and terminate it manually.")
179 except:
180 pass
182 raise ProvisioningError("Warning: Another slapd Instance seems already running on this host, listening to " + self.ldapi_uri + ". Please shut it down before you continue. ")
184 except LdbError, e:
185 pass
187 # Try to print helpful messages when the user has not specified the path to slapd
188 if self.slapd_path is None:
189 raise ProvisioningError("Warning: LDAP-Backend must be setup with path to slapd, e.g. --slapd-path=\"/usr/local/libexec/slapd\"!")
190 if not os.path.exists(self.slapd_path):
191 self.message (self.slapd_path)
192 raise ProvisioningError("Warning: Given Path to slapd does not exist!")
195 if not os.path.isdir(self.paths.ldapdir):
196 os.makedirs(self.paths.ldapdir, 0700)
198 # Put the LDIF of the schema into a database so we can search on
199 # it to generate schema-dependent configurations in Fedora DS and
200 # OpenLDAP
201 schemadb_path = os.path.join(self.paths.ldapdir, "schema-tmp.ldb")
202 try:
203 os.unlink(schemadb_path)
204 except OSError:
205 pass
207 self.schema.write_to_tmp_ldb(schemadb_path);
209 self.credentials = Credentials()
210 self.credentials.guess(self.lp)
211 #Kerberos to an ldapi:// backend makes no sense
212 self.credentials.set_kerberos_state(DONT_USE_KERBEROS)
213 self.credentials.set_password(self.ldapadminpass)
215 self.secrets_credentials = Credentials()
216 self.secrets_credentials.guess(self.lp)
217 #Kerberos to an ldapi:// backend makes no sense
218 self.secrets_credentials.set_kerberos_state(DONT_USE_KERBEROS)
219 self.secrets_credentials.set_username("samba-admin")
220 self.secrets_credentials.set_password(self.ldapadminpass)
222 self.provision()
224 def provision(self):
225 pass
227 def start(self):
228 self.slapd_command_escaped = "\'" + "\' \'".join(self.slapd_command) + "\'"
229 setup_file(self.setup_path("ldap_backend_startup.sh"), self.paths.ldapdir + "/ldap_backend_startup.sh", {
230 "SLAPD_COMMAND" : self.slapd_command_escaped})
232 # Now start the slapd, so we can provision onto it. We keep the
233 # subprocess context around, to kill this off at the successful
234 # end of the script
235 self.slapd = subprocess.Popen(self.slapd_provision_command, close_fds=True, shell=False)
237 while self.slapd.poll() is None:
238 # Wait until the socket appears
239 try:
240 ldapi_db = Ldb(self.ldapi_uri, lp=self.lp, credentials=self.credentials)
241 search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
242 expression="(objectClass=OpenLDAProotDSE)")
243 # If we have got here, then we must have a valid connection to the LDAP server!
244 return
245 except LdbError, e:
246 time.sleep(1)
247 pass
249 raise ProvisioningError("slapd died before we could make a connection to it")
251 def shutdown(self):
252 # if an LDAP backend is in use, terminate slapd after final provision and check its proper termination
253 if self.slapd.poll() is None:
254 #Kill the slapd
255 if hasattr(self.slapd, "terminate"):
256 self.slapd.terminate()
257 else:
258 # Older python versions don't have .terminate()
259 import signal
260 os.kill(self.slapd.pid, signal.SIGTERM)
262 #and now wait for it to die
263 self.slapd.communicate()
266 class OpenLDAPBackend(LDAPBackend):
267 def __init__(self, backend_type, paths=None, setup_path=None, lp=None, credentials=None,
268 names=None, message=None,
269 domainsid=None,
270 schema=None,
271 hostname=None,
272 ldapadminpass=None,
273 slapd_path=None,
274 ldap_backend_extra_port=None,
275 ldap_dryrun_mode=False,
276 ol_mmr_urls=None,
277 nosync=False):
279 super(OpenLDAPBackend, self).__init__(
280 backend_type=backend_type,
281 paths=paths, setup_path=setup_path,
282 lp=lp, credentials=credentials,
283 names=names,
284 message=message,
285 domainsid=domainsid,
286 schema=schema,
287 hostname=hostname,
288 ldapadminpass=ldapadminpass,
289 slapd_path=slapd_path,
290 ldap_backend_extra_port=ldap_backend_extra_port,
291 ldap_dryrun_mode=ldap_dryrun_mode)
293 self.ol_mmr_urls = ol_mmr_urls
294 self.nosync = nosync
296 self.schema = Schema(
297 self.setup_path,
298 self.domainsid,
299 schemadn=self.names.schemadn,
300 serverdn=self.names.serverdn,
301 files=[setup_path("schema_samba4.ldif")]);
303 def provision(self):
304 # Wipe the directories so we can start
305 shutil.rmtree(os.path.join(self.paths.ldapdir, "db"), True)
307 #Allow the test scripts to turn off fsync() for OpenLDAP as for TDB and LDB
308 nosync_config = ""
309 if self.nosync:
310 nosync_config = "dbnosync"
312 lnkattr = self.schema.linked_attributes()
313 refint_attributes = ""
314 memberof_config = "# Generated from Samba4 schema\n"
315 for att in lnkattr.keys():
316 if lnkattr[att] is not None:
317 refint_attributes = refint_attributes + " " + att
319 memberof_config += read_and_sub_file(self.setup_path("memberof.conf"),
320 { "MEMBER_ATTR" : att ,
321 "MEMBEROF_ATTR" : lnkattr[att] })
323 refint_config = read_and_sub_file(self.setup_path("refint.conf"),
324 { "LINK_ATTRS" : refint_attributes})
326 attrs = ["linkID", "lDAPDisplayName"]
327 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)
328 index_config = ""
329 for i in range (0, len(res)):
330 index_attr = res[i]["lDAPDisplayName"][0]
331 if index_attr == "objectGUID":
332 index_attr = "entryUUID"
334 index_config += "index " + index_attr + " eq\n"
336 # generate serverids, ldap-urls and syncrepl-blocks for mmr hosts
337 mmr_on_config = ""
338 mmr_replicator_acl = ""
339 mmr_serverids_config = ""
340 mmr_syncrepl_schema_config = ""
341 mmr_syncrepl_config_config = ""
342 mmr_syncrepl_user_config = ""
345 if self.ol_mmr_urls is not None:
346 # For now, make these equal
347 mmr_pass = self.ldapadminpass
349 url_list=filter(None,self.ol_mmr_urls.split(' '))
350 if (len(url_list) == 1):
351 url_list=filter(None,self.ol_mmr_urls.split(','))
354 mmr_on_config = "MirrorMode On"
355 mmr_replicator_acl = " by dn=cn=replicator,cn=samba read"
356 serverid=0
357 for url in url_list:
358 serverid=serverid+1
359 mmr_serverids_config += read_and_sub_file(self.setup_path("mmr_serverids.conf"),
360 { "SERVERID" : str(serverid),
361 "LDAPSERVER" : url })
362 rid=serverid*10
363 rid=rid+1
364 mmr_syncrepl_schema_config += read_and_sub_file(self.setup_path("mmr_syncrepl.conf"),
365 { "RID" : str(rid),
366 "MMRDN": self.names.schemadn,
367 "LDAPSERVER" : url,
368 "MMR_PASSWORD": mmr_pass})
370 rid=rid+1
371 mmr_syncrepl_config_config += read_and_sub_file(self.setup_path("mmr_syncrepl.conf"),
372 { "RID" : str(rid),
373 "MMRDN": self.names.configdn,
374 "LDAPSERVER" : url,
375 "MMR_PASSWORD": mmr_pass})
377 rid=rid+1
378 mmr_syncrepl_user_config += read_and_sub_file(self.setup_path("mmr_syncrepl.conf"),
379 { "RID" : str(rid),
380 "MMRDN": self.names.domaindn,
381 "LDAPSERVER" : url,
382 "MMR_PASSWORD": mmr_pass })
383 # OpenLDAP cn=config initialisation
384 olc_syncrepl_config = ""
385 olc_mmr_config = ""
386 # if mmr = yes, generate cn=config-replication directives
387 # and olc_seed.lif for the other mmr-servers
388 if self.ol_mmr_urls is not None:
389 serverid=0
390 olc_serverids_config = ""
391 olc_syncrepl_seed_config = ""
392 olc_mmr_config += read_and_sub_file(self.setup_path("olc_mmr.conf"),{})
393 rid=1000
394 for url in url_list:
395 serverid=serverid+1
396 olc_serverids_config += read_and_sub_file(self.setup_path("olc_serverid.conf"),
397 { "SERVERID" : str(serverid),
398 "LDAPSERVER" : url })
400 rid=rid+1
401 olc_syncrepl_config += read_and_sub_file(self.setup_path("olc_syncrepl.conf"),
402 { "RID" : str(rid),
403 "LDAPSERVER" : url,
404 "MMR_PASSWORD": mmr_pass})
406 olc_syncrepl_seed_config += read_and_sub_file(self.setup_path("olc_syncrepl_seed.conf"),
407 { "RID" : str(rid),
408 "LDAPSERVER" : url})
410 setup_file(self.setup_path("olc_seed.ldif"), self.paths.olcseedldif,
411 {"OLC_SERVER_ID_CONF": olc_serverids_config,
412 "OLC_PW": self.ldapadminpass,
413 "OLC_SYNCREPL_CONF": olc_syncrepl_seed_config})
414 # end olc
416 setup_file(self.setup_path("slapd.conf"), self.paths.slapdconf,
417 {"DNSDOMAIN": self.names.dnsdomain,
418 "LDAPDIR": self.paths.ldapdir,
419 "DOMAINDN": self.names.domaindn,
420 "CONFIGDN": self.names.configdn,
421 "SCHEMADN": self.names.schemadn,
422 "MEMBEROF_CONFIG": memberof_config,
423 "MIRRORMODE": mmr_on_config,
424 "REPLICATOR_ACL": mmr_replicator_acl,
425 "MMR_SERVERIDS_CONFIG": mmr_serverids_config,
426 "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config,
427 "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config,
428 "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config,
429 "OLC_SYNCREPL_CONFIG": olc_syncrepl_config,
430 "OLC_MMR_CONFIG": olc_mmr_config,
431 "REFINT_CONFIG": refint_config,
432 "INDEX_CONFIG": index_config,
433 "NOSYNC": nosync_config})
435 setup_db_config(self.setup_path, os.path.join(self.paths.ldapdir, "db", "user"))
436 setup_db_config(self.setup_path, os.path.join(self.paths.ldapdir, "db", "config"))
437 setup_db_config(self.setup_path, os.path.join(self.paths.ldapdir, "db", "schema"))
439 if not os.path.exists(os.path.join(self.paths.ldapdir, "db", "samba", "cn=samba")):
440 os.makedirs(os.path.join(self.paths.ldapdir, "db", "samba", "cn=samba"), 0700)
442 setup_file(self.setup_path("cn=samba.ldif"),
443 os.path.join(self.paths.ldapdir, "db", "samba", "cn=samba.ldif"),
444 { "UUID": str(uuid.uuid4()),
445 "LDAPTIME": timestring(int(time.time()))} )
446 setup_file(self.setup_path("cn=samba-admin.ldif"),
447 os.path.join(self.paths.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
448 {"LDAPADMINPASS_B64": b64encode(self.ldapadminpass),
449 "UUID": str(uuid.uuid4()),
450 "LDAPTIME": timestring(int(time.time()))} )
452 if self.ol_mmr_urls is not None:
453 setup_file(self.setup_path("cn=replicator.ldif"),
454 os.path.join(self.paths.ldapdir, "db", "samba", "cn=samba", "cn=replicator.ldif"),
455 {"MMR_PASSWORD_B64": b64encode(mmr_pass),
456 "UUID": str(uuid.uuid4()),
457 "LDAPTIME": timestring(int(time.time()))} )
460 mapping = "schema-map-openldap-2.3"
461 backend_schema = "backend-schema.schema"
463 backend_schema_data = self.schema.ldb.convert_schema_to_openldap("openldap", open(self.setup_path(mapping), 'r').read())
464 assert backend_schema_data is not None
465 open(os.path.join(self.paths.ldapdir, backend_schema), 'w').write(backend_schema_data)
467 # now we generate the needed strings to start slapd automatically,
468 # first ldapi_uri...
469 if self.ldap_backend_extra_port is not None:
470 # When we use MMR, we can't use 0.0.0.0 as it uses the name
471 # specified there as part of it's clue as to it's own name,
472 # and not to replicate to itself
473 if self.ol_mmr_urls is None:
474 server_port_string = "ldap://0.0.0.0:%d" % self.ldap_backend_extra_port
475 else:
476 server_port_string = "ldap://" + self.names.hostname + "." + self.names.dnsdomain +":%d" % self.ldap_backend_extra_port
477 else:
478 server_port_string = ""
480 # Prepare the 'result' information - the commands to return in particular
481 self.slapd_provision_command = [self.slapd_path]
483 self.slapd_provision_command.append("-F" + self.paths.olcdir)
485 self.slapd_provision_command.append("-h")
487 # copy this command so we have two version, one with -d0 and only ldapi, and one with all the listen commands
488 self.slapd_command = list(self.slapd_provision_command)
490 self.slapd_provision_command.append(self.ldapi_uri)
491 self.slapd_provision_command.append("-d0")
493 uris = self.ldapi_uri
494 if server_port_string is not "":
495 uris = uris + " " + server_port_string
497 self.slapd_command.append(uris)
499 # Set the username - done here because Fedora DS still uses the admin DN and simple bind
500 self.credentials.set_username("samba-admin")
502 # If we were just looking for crashes up to this point, it's a
503 # good time to exit before we realise we don't have OpenLDAP on
504 # this system
505 if self.ldap_dryrun_mode:
506 sys.exit(0)
508 # Finally, convert the configuration into cn=config style!
509 if not os.path.isdir(self.paths.olcdir):
510 os.makedirs(self.paths.olcdir, 0770)
512 retcode = subprocess.call([self.slapd_path, "-Ttest", "-f", self.paths.slapdconf, "-F", self.paths.olcdir], close_fds=True, shell=False)
514 # We can't do this, as OpenLDAP is strange. It gives an error
515 # output to the above, but does the conversion sucessfully...
517 # if retcode != 0:
518 # raise ProvisioningError("conversion from slapd.conf to cn=config failed")
520 if not os.path.exists(os.path.join(self.paths.olcdir, "cn=config.ldif")):
521 raise ProvisioningError("conversion from slapd.conf to cn=config failed")
523 # Don't confuse the admin by leaving the slapd.conf around
524 os.remove(self.paths.slapdconf)
527 class FDSBackend(LDAPBackend):
528 def __init__(self, backend_type, paths=None, setup_path=None, lp=None, credentials=None,
529 names=None, message=None,
530 domainsid=None,
531 schema=None,
532 hostname=None,
533 ldapadminpass=None,
534 slapd_path=None,
535 ldap_backend_extra_port=None,
536 ldap_dryrun_mode=False,
537 root=None,
538 setup_ds_path=None):
540 super(FDSBackend, self).__init__(
541 backend_type=backend_type,
542 paths=paths, setup_path=setup_path,
543 lp=lp, credentials=credentials,
544 names=names,
545 message=message,
546 domainsid=domainsid,
547 schema=schema,
548 hostname=hostname,
549 ldapadminpass=ldapadminpass,
550 slapd_path=slapd_path,
551 ldap_backend_extra_port=ldap_backend_extra_port,
552 ldap_dryrun_mode=ldap_dryrun_mode)
554 self.root = root
555 self.setup_ds_path = setup_ds_path
557 self.sambadn = "CN=Samba"
559 self.fedoradsinf = os.path.join(paths.ldapdir, "fedorads.inf")
560 self.partitions_ldif = os.path.join(paths.ldapdir, "fedorads-partitions.ldif")
561 self.sasl_ldif = os.path.join(paths.ldapdir, "fedorads-sasl.ldif")
562 self.dna_ldif = os.path.join(paths.ldapdir, "fedorads-dna.ldif")
563 self.pam_ldif = os.path.join(paths.ldapdir, "fedorads-pam.ldif")
564 self.refint_ldif = os.path.join(paths.ldapdir, "fedorads-refint.ldif")
565 self.linked_attrs_ldif = os.path.join(paths.ldapdir, "fedorads-linked-attributes.ldif")
566 self.index_ldif = os.path.join(paths.ldapdir, "fedorads-index.ldif")
567 self.samba_ldif = os.path.join(paths.ldapdir, "fedorads-samba.ldif")
569 self.samba3_schema = self.setup_path("../../examples/LDAP/samba.schema")
570 self.samba3_ldif = os.path.join(self.paths.ldapdir, "samba3.ldif")
572 self.retcode = subprocess.call(["bin/oLschema2ldif", "-H", "NONE",
573 "-I", self.samba3_schema,
574 "-O", self.samba3_ldif,
575 "-b", self.names.domaindn],
576 close_fds=True, shell=False)
578 if self.retcode != 0:
579 raise Exception("Unable to convert Samba 3 schema.")
581 self.schema = Schema(
582 self.setup_path,
583 self.domainsid,
584 schemadn=self.names.schemadn,
585 serverdn=self.names.serverdn,
586 files=[setup_path("schema_samba4.ldif"), self.samba3_ldif],
587 prefixmap=["1000:1.3.6.1.4.1.7165.2.1", "1001:1.3.6.1.4.1.7165.2.2"])
589 def provision(self):
590 if self.ldap_backend_extra_port is not None:
591 serverport = "ServerPort=%d" % self.ldap_backend_extra_port
592 else:
593 serverport = ""
595 setup_file(self.setup_path("fedorads.inf"), self.fedoradsinf,
596 {"ROOT": self.root,
597 "HOSTNAME": self.hostname,
598 "DNSDOMAIN": self.names.dnsdomain,
599 "LDAPDIR": self.paths.ldapdir,
600 "DOMAINDN": self.names.domaindn,
601 "LDAPMANAGERDN": self.names.ldapmanagerdn,
602 "LDAPMANAGERPASS": self.ldapadminpass,
603 "SERVERPORT": serverport})
605 setup_file(self.setup_path("fedorads-partitions.ldif"), self.partitions_ldif,
606 {"CONFIGDN": self.names.configdn,
607 "SCHEMADN": self.names.schemadn,
608 "SAMBADN": self.sambadn,
611 setup_file(self.setup_path("fedorads-sasl.ldif"), self.sasl_ldif,
612 {"SAMBADN": self.sambadn,
615 setup_file(self.setup_path("fedorads-dna.ldif"), self.dna_ldif,
616 {"DOMAINDN": self.names.domaindn,
617 "SAMBADN": self.sambadn,
618 "DOMAINSID": str(self.domainsid),
621 setup_file(self.setup_path("fedorads-pam.ldif"), self.pam_ldif)
623 lnkattr = self.schema.linked_attributes()
625 refint_config = data = open(self.setup_path("fedorads-refint-delete.ldif"), 'r').read()
626 memberof_config = ""
627 index_config = ""
628 argnum = 3
630 for attr in lnkattr.keys():
631 if lnkattr[attr] is not None:
632 refint_config += read_and_sub_file(self.setup_path("fedorads-refint-add.ldif"),
633 { "ARG_NUMBER" : str(argnum) ,
634 "LINK_ATTR" : attr })
635 memberof_config += read_and_sub_file(self.setup_path("fedorads-linked-attributes.ldif"),
636 { "MEMBER_ATTR" : attr ,
637 "MEMBEROF_ATTR" : lnkattr[attr] })
638 index_config += read_and_sub_file(self.setup_path("fedorads-index.ldif"),
639 { "ATTR" : attr })
640 argnum += 1
642 open(self.refint_ldif, 'w').write(refint_config)
643 open(self.linked_attrs_ldif, 'w').write(memberof_config)
645 attrs = ["lDAPDisplayName"]
646 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)
648 for i in range (0, len(res)):
649 attr = res[i]["lDAPDisplayName"][0]
651 if attr == "objectGUID":
652 attr = "nsUniqueId"
654 index_config += read_and_sub_file(self.setup_path("fedorads-index.ldif"),
655 { "ATTR" : attr })
657 open(self.index_ldif, 'w').write(index_config)
659 setup_file(self.setup_path("fedorads-samba.ldif"), self.samba_ldif,
660 {"SAMBADN": self.sambadn,
661 "LDAPADMINPASS": self.ldapadminpass
664 mapping = "schema-map-fedora-ds-1.0"
665 backend_schema = "99_ad.ldif"
667 # Build a schema file in Fedora DS format
668 backend_schema_data = self.schema.ldb.convert_schema_to_openldap("fedora-ds", open(self.setup_path(mapping), 'r').read())
669 assert backend_schema_data is not None
670 open(os.path.join(self.paths.ldapdir, backend_schema), 'w').write(backend_schema_data)
672 self.credentials.set_bind_dn(self.names.ldapmanagerdn)
674 # Destory the target directory, or else setup-ds.pl will complain
675 fedora_ds_dir = os.path.join(self.paths.ldapdir, "slapd-samba4")
676 shutil.rmtree(fedora_ds_dir, True)
678 self.slapd_provision_command = [self.slapd_path, "-D", fedora_ds_dir, "-i", self.paths.slapdpid];
679 #In the 'provision' command line, stay in the foreground so we can easily kill it
680 self.slapd_provision_command.append("-d0")
682 #the command for the final run is the normal script
683 self.slapd_command = [os.path.join(self.paths.ldapdir, "slapd-samba4", "start-slapd")]
685 # If we were just looking for crashes up to this point, it's a
686 # good time to exit before we realise we don't have Fedora DS on
687 if self.ldap_dryrun_mode:
688 sys.exit(0)
690 # Try to print helpful messages when the user has not specified the path to the setup-ds tool
691 if self.setup_ds_path is None:
692 raise ProvisioningError("Warning: Fedora DS LDAP-Backend must be setup with path to setup-ds, e.g. --setup-ds-path=\"/usr/sbin/setup-ds.pl\"!")
693 if not os.path.exists(self.setup_ds_path):
694 self.message (self.setup_ds_path)
695 raise ProvisioningError("Warning: Given Path to slapd does not exist!")
697 # Run the Fedora DS setup utility
698 retcode = subprocess.call([self.setup_ds_path, "--silent", "--file", self.fedoradsinf], close_fds=True, shell=False)
699 if retcode != 0:
700 raise ProvisioningError("setup-ds failed")
702 # Load samba-admin
703 retcode = subprocess.call([
704 os.path.join(self.paths.ldapdir, "slapd-samba4", "ldif2db"), "-s", self.sambadn, "-i", self.samba_ldif],
705 close_fds=True, shell=False)
706 if retcode != 0:
707 raise("ldif2db failed")
709 def post_setup(self):
710 ldapi_db = Ldb(self.ldapi_uri, credentials=self.credentials)
712 # delete default SASL mappings
713 res = ldapi_db.search(expression="(!(cn=samba-admin mapping))", base="cn=mapping,cn=sasl,cn=config", scope=SCOPE_ONELEVEL, attrs=["dn"])
715 # configure in-directory access control on Fedora DS via the aci attribute (over a direct ldapi:// socket)
716 for i in range (0, len(res)):
717 dn = str(res[i]["dn"])
718 ldapi_db.delete(dn)
720 aci = """(targetattr = "*") (version 3.0;acl "full access to all by samba-admin";allow (all)(userdn = "ldap:///CN=samba-admin,%s");)""" % self.sambadn
722 m = ldb.Message()
723 m["aci"] = ldb.MessageElement([aci], ldb.FLAG_MOD_REPLACE, "aci")
725 m.dn = ldb.Dn(1, self.names.domaindn)
726 ldapi_db.modify(m)
728 m.dn = ldb.Dn(1, self.names.configdn)
729 ldapi_db.modify(m)
731 m.dn = ldb.Dn(1, self.names.schemadn)
732 ldapi_db.modify(m)