s4:provision Remove LDB backend files in provision
[ira/wip.git] / source4 / scripting / python / samba / provisionbackend.py
1 #
2 # Unix SMB/CIFS implementation.
3 # backend code for provisioning a Samba4 server
4
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
8 #
9 # Based on the original in EJS:
10 # Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
11 #
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.
16 #   
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.
21 #   
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/>.
24 #
25
26 """Functions for setting up a Samba configuration (LDB and LDAP backends)."""
27
28 from base64 import b64encode
29 import os
30 import sys
31 import uuid
32 import time
33 import shutil
34
35 from samba import read_and_sub_file
36 from samba import Ldb
37 import urllib
38 from ldb import SCOPE_BASE, SCOPE_ONELEVEL, LdbError, timestring
39 from credentials import Credentials, DONT_USE_KERBEROS
40 from samba import setup_file
41
42 def setup_db_config(setup_path, dbdir):
43     """Setup a Berkeley database.
44     
45     :param setup_path: Setup path function.
46     :param dbdir: Database directory."""
47     if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
48         os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
49         if not os.path.isdir(os.path.join(dbdir, "tmp")):
50             os.makedirs(os.path.join(dbdir, "tmp"), 0700)
51
52     setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"),
53                {"LDAPDBDIR": dbdir})
54
55 class ProvisionBackend(object):
56     def __init__(self, backend_type, paths=None, setup_path=None, lp=None, credentials=None, 
57                  names=None, message=None, 
58                  hostname=None, root=None, 
59                  schema=None, ldapadminpass=None,
60                  ldap_backend_extra_port=None,
61                  ol_mmr_urls=None, 
62                  setup_ds_path=None, slapd_path=None, 
63                  nosync=False, ldap_dryrun_mode=False,
64                  domainsid=None):
65         """Provision an LDAP backend for samba4
66         
67         This works for OpenLDAP and Fedora DS
68         """
69         self.paths = paths
70         self.slapd_command = None
71         self.slapd_command_escaped = None
72
73         self.type = backend_type
74         
75         # Set a default - the code for "existing" below replaces this
76         self.ldap_backend_type = backend_type
77
78         self.post_setup = None
79         self.shutdown = None
80
81         if self.type is "ldb":
82             self.credentials = None
83             self.secrets_credentials = None
84     
85             # Wipe the old sam.ldb databases away
86             shutil.rmtree(paths.samdb + ".d", True)
87             return
88
89         self.ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.ldapdir, "ldapi"), safe="")
90         
91         if self.type == "existing":
92             #Check to see that this 'existing' LDAP backend in fact exists
93             ldapi_db = Ldb(self.ldapi_uri, credentials=credentials)
94             search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
95                                                 expression="(objectClass=OpenLDAProotDSE)")
96
97             # If we have got here, then we must have a valid connection to the LDAP server, with valid credentials supplied
98             self.credentials = credentials
99             # This caused them to be set into the long-term database later in the script.
100             self.secrets_credentials = credentials
101
102             self.ldap_backend_type = "openldap" #For now, assume existing backends at least emulate OpenLDAP
103             return
104     
105         # we will shortly start slapd with ldapi for final provisioning. first check with ldapsearch -> rootDSE via self.ldapi_uri
106         # if another instance of slapd is already running 
107         try:
108             ldapi_db = Ldb(self.ldapi_uri)
109             search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
110                                                 expression="(objectClass=OpenLDAProotDSE)");
111             try:
112                 f = open(paths.slapdpid, "r")
113                 p = f.read()
114                 f.close()
115                 message("Check for slapd Process with PID: " + str(p) + " and terminate it manually.")
116             except:
117                 pass
118             
119             raise ProvisioningError("Warning: Another slapd Instance seems already running on this host, listening to " + self.ldapi_uri + ". Please shut it down before you continue. ")
120         
121         except LdbError, e:
122             pass
123
124         # Try to print helpful messages when the user has not specified the path to slapd
125         if slapd_path is None:
126             raise ProvisioningError("Warning: LDAP-Backend must be setup with path to slapd, e.g. --slapd-path=\"/usr/local/libexec/slapd\"!")
127         if not os.path.exists(slapd_path):
128             message (slapd_path)
129             raise ProvisioningError("Warning: Given Path to slapd does not exist!")
130
131
132         if not os.path.isdir(paths.ldapdir):
133             os.makedirs(paths.ldapdir, 0700)
134
135         # Put the LDIF of the schema into a database so we can search on
136         # it to generate schema-dependent configurations in Fedora DS and
137         # OpenLDAP
138         schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb")
139         try:
140             os.unlink(schemadb_path)
141         except OSError:
142             pass
143
144         schema.write_to_tmp_ldb(schemadb_path);
145
146         self.credentials = Credentials()
147         self.credentials.guess(lp)
148         #Kerberos to an ldapi:// backend makes no sense
149         self.credentials.set_kerberos_state(DONT_USE_KERBEROS)
150
151         self.secrets_credentials = Credentials()
152         self.secrets_credentials.guess(lp)
153         #Kerberos to an ldapi:// backend makes no sense
154         self.secrets_credentials.set_kerberos_state(DONT_USE_KERBEROS)
155
156
157         def ldap_backend_shutdown(self):
158             # if an LDAP backend is in use, terminate slapd after final provision and check its proper termination
159             if self.slapd.poll() is None:
160                 #Kill the slapd
161                 if hasattr(self.slapd, "terminate"):
162                     self.slapd.terminate()
163                 else:
164                     # Older python versions don't have .terminate()
165                     import signal
166                     os.kill(self.slapd.pid, signal.SIGTERM)
167             
168                 #and now wait for it to die
169                 self.slapd.communicate()
170
171         self.shutdown = ldap_backend_shutdown
172
173         if self.type == "fedora-ds":
174             provision_fds_backend(self, setup_path=setup_path,
175                                   names=names, message=message, 
176                                   hostname=hostname,
177                                   ldapadminpass=ldapadminpass, root=root, 
178                                   schema=schema,
179                                   ldap_backend_extra_port=ldap_backend_extra_port, 
180                                   setup_ds_path=setup_ds_path,
181                                   slapd_path=slapd_path,
182                                   nosync=nosync,
183                                   ldap_dryrun_mode=ldap_dryrun_mode,
184                                   domainsid=domainsid)
185             
186         elif self.type == "openldap":
187             provision_openldap_backend(self, setup_path=setup_path,
188                                        names=names, message=message, 
189                                        hostname=hostname,
190                                        ldapadminpass=ldapadminpass, root=root, 
191                                        schema=schema,
192                                        ldap_backend_extra_port=ldap_backend_extra_port, 
193                                        ol_mmr_urls=ol_mmr_urls, 
194                                        slapd_path=slapd_path,
195                                        nosync=nosync,
196                                        ldap_dryrun_mode=ldap_dryrun_mode)
197         else:
198             raise ProvisioningError("Unknown LDAP backend type selected")
199
200         self.credentials.set_password(ldapadminpass)
201         self.secrets_credentials.set_username("samba-admin")
202         self.secrets_credentials.set_password(ldapadminpass)
203
204         self.slapd_command_escaped = "\'" + "\' \'".join(self.slapd_command) + "\'"
205         setup_file(setup_path("ldap_backend_startup.sh"), paths.ldapdir + "/ldap_backend_startup.sh", {
206                 "SLAPD_COMMAND" : slapd_command})
207
208         # Now start the slapd, so we can provision onto it.  We keep the
209         # subprocess context around, to kill this off at the successful
210         # end of the script
211         self.slapd = subprocess.Popen(self.slapd_provision_command, close_fds=True, shell=False)
212     
213         while self.slapd.poll() is None:
214             # Wait until the socket appears
215             try:
216                 ldapi_db = Ldb(self.ldapi_uri, lp=lp, credentials=self.credentials)
217                 search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
218                                                     expression="(objectClass=OpenLDAProotDSE)")
219                 # If we have got here, then we must have a valid connection to the LDAP server!
220                 return
221             except LdbError, e:
222                 time.sleep(1)
223                 pass
224         
225         raise ProvisioningError("slapd died before we could make a connection to it")
226
227
228 def provision_openldap_backend(result, setup_path=None, names=None,
229                                message=None, 
230                                hostname=None, ldapadminpass=None, root=None, 
231                                schema=None, 
232                                ldap_backend_extra_port=None,
233                                ol_mmr_urls=None, 
234                                slapd_path=None, nosync=False,
235                                ldap_dryrun_mode=False):
236
237     # Wipe the directories so we can start
238     shutil.rmtree(os.path.join(result.paths.ldapdir, "db"), True)
239
240     #Allow the test scripts to turn off fsync() for OpenLDAP as for TDB and LDB
241     nosync_config = ""
242     if nosync:
243         nosync_config = "dbnosync"
244         
245     lnkattr = schema.linked_attributes()
246     refint_attributes = ""
247     memberof_config = "# Generated from Samba4 schema\n"
248     for att in  lnkattr.keys():
249         if lnkattr[att] is not None:
250             refint_attributes = refint_attributes + " " + att 
251             
252             memberof_config += read_and_sub_file(setup_path("memberof.conf"),
253                                                  { "MEMBER_ATTR" : att ,
254                                                    "MEMBEROF_ATTR" : lnkattr[att] })
255             
256     refint_config = read_and_sub_file(setup_path("refint.conf"),
257                                       { "LINK_ATTRS" : refint_attributes})
258     
259     attrs = ["linkID", "lDAPDisplayName"]
260     res = schema.ldb.search(expression="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base=names.schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
261     index_config = ""
262     for i in range (0, len(res)):
263         index_attr = res[i]["lDAPDisplayName"][0]
264         if index_attr == "objectGUID":
265             index_attr = "entryUUID"
266             
267         index_config += "index " + index_attr + " eq\n"
268
269 # generate serverids, ldap-urls and syncrepl-blocks for mmr hosts
270     mmr_on_config = ""
271     mmr_replicator_acl = ""
272     mmr_serverids_config = ""
273     mmr_syncrepl_schema_config = "" 
274     mmr_syncrepl_config_config = "" 
275     mmr_syncrepl_user_config = "" 
276        
277     
278     if ol_mmr_urls is not None:
279         # For now, make these equal
280         mmr_pass = ldapadminpass
281         
282         url_list=filter(None,ol_mmr_urls.split(' ')) 
283         if (len(url_list) == 1):
284             url_list=filter(None,ol_mmr_urls.split(',')) 
285                      
286             
287             mmr_on_config = "MirrorMode On"
288             mmr_replicator_acl = "  by dn=cn=replicator,cn=samba read"
289             serverid=0
290             for url in url_list:
291                 serverid=serverid+1
292                 mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"),
293                                                           { "SERVERID" : str(serverid),
294                                                             "LDAPSERVER" : url })
295                 rid=serverid*10
296                 rid=rid+1
297                 mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
298                                                                 {  "RID" : str(rid),
299                                                                    "MMRDN": names.schemadn,
300                                                                    "LDAPSERVER" : url,
301                                                                    "MMR_PASSWORD": mmr_pass})
302                 
303                 rid=rid+1
304                 mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
305                                                                 {  "RID" : str(rid),
306                                                                    "MMRDN": names.configdn,
307                                                                    "LDAPSERVER" : url,
308                                                                    "MMR_PASSWORD": mmr_pass})
309                 
310                 rid=rid+1
311                 mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
312                                                               {  "RID" : str(rid),
313                                                                  "MMRDN": names.domaindn,
314                                                                  "LDAPSERVER" : url,
315                                                                  "MMR_PASSWORD": mmr_pass })
316     # OpenLDAP cn=config initialisation
317     olc_syncrepl_config = ""
318     olc_mmr_config = "" 
319     # if mmr = yes, generate cn=config-replication directives
320     # and olc_seed.lif for the other mmr-servers
321     if ol_mmr_urls is not None:
322         serverid=0
323         olc_serverids_config = ""
324         olc_syncrepl_seed_config = ""
325         olc_mmr_config += read_and_sub_file(setup_path("olc_mmr.conf"),{})
326         rid=1000
327         for url in url_list:
328             serverid=serverid+1
329             olc_serverids_config += read_and_sub_file(setup_path("olc_serverid.conf"),
330                                                       { "SERVERID" : str(serverid),
331                                                         "LDAPSERVER" : url })
332             
333             rid=rid+1
334             olc_syncrepl_config += read_and_sub_file(setup_path("olc_syncrepl.conf"),
335                                                      {  "RID" : str(rid),
336                                                         "LDAPSERVER" : url,
337                                                         "MMR_PASSWORD": mmr_pass})
338             
339             olc_syncrepl_seed_config += read_and_sub_file(setup_path("olc_syncrepl_seed.conf"),
340                                                           {  "RID" : str(rid),
341                                                              "LDAPSERVER" : url})
342                 
343         setup_file(setup_path("olc_seed.ldif"), result.paths.olcseedldif,
344                    {"OLC_SERVER_ID_CONF": olc_serverids_config,
345                     "OLC_PW": ldapadminpass,
346                     "OLC_SYNCREPL_CONF": olc_syncrepl_seed_config})
347     # end olc
348                 
349     setup_file(setup_path("slapd.conf"), result.paths.slapdconf,
350                {"DNSDOMAIN": names.dnsdomain,
351                 "LDAPDIR": result.paths.ldapdir,
352                 "DOMAINDN": names.domaindn,
353                 "CONFIGDN": names.configdn,
354                 "SCHEMADN": names.schemadn,
355                 "MEMBEROF_CONFIG": memberof_config,
356                 "MIRRORMODE": mmr_on_config,
357                 "REPLICATOR_ACL": mmr_replicator_acl,
358                 "MMR_SERVERIDS_CONFIG": mmr_serverids_config,
359                 "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config,
360                 "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config,
361                 "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config,
362                 "OLC_SYNCREPL_CONFIG": olc_syncrepl_config,
363                 "OLC_MMR_CONFIG": olc_mmr_config,
364                 "REFINT_CONFIG": refint_config,
365                 "INDEX_CONFIG": index_config,
366                 "NOSYNC": nosync_config})
367         
368     setup_db_config(setup_path, os.path.join(result.paths.ldapdir, "db", "user"))
369     setup_db_config(setup_path, os.path.join(result.paths.ldapdir, "db", "config"))
370     setup_db_config(setup_path, os.path.join(result.paths.ldapdir, "db", "schema"))
371     
372     if not os.path.exists(os.path.join(result.paths.ldapdir, "db", "samba",  "cn=samba")):
373         os.makedirs(os.path.join(result.paths.ldapdir, "db", "samba",  "cn=samba"), 0700)
374         
375     setup_file(setup_path("cn=samba.ldif"), 
376                os.path.join(result.paths.ldapdir, "db", "samba",  "cn=samba.ldif"),
377                { "UUID": str(uuid.uuid4()), 
378                  "LDAPTIME": timestring(int(time.time()))} )
379     setup_file(setup_path("cn=samba-admin.ldif"), 
380                os.path.join(result.paths.ldapdir, "db", "samba",  "cn=samba", "cn=samba-admin.ldif"),
381                {"LDAPADMINPASS_B64": b64encode(ldapadminpass),
382                 "UUID": str(uuid.uuid4()), 
383                 "LDAPTIME": timestring(int(time.time()))} )
384     
385     if ol_mmr_urls is not None:
386         setup_file(setup_path("cn=replicator.ldif"),
387                    os.path.join(result.paths.ldapdir, "db", "samba",  "cn=samba", "cn=replicator.ldif"),
388                    {"MMR_PASSWORD_B64": b64encode(mmr_pass),
389                     "UUID": str(uuid.uuid4()),
390                     "LDAPTIME": timestring(int(time.time()))} )
391         
392
393     mapping = "schema-map-openldap-2.3"
394     backend_schema = "backend-schema.schema"
395
396     backend_schema_data = schema.ldb.convert_schema_to_openldap("openldap", open(setup_path(mapping), 'r').read())
397     assert backend_schema_data is not None
398     open(os.path.join(result.paths.ldapdir, backend_schema), 'w').write(backend_schema_data)
399
400     # now we generate the needed strings to start slapd automatically,
401     # first ldapi_uri...
402     if ldap_backend_extra_port is not None:
403         # When we use MMR, we can't use 0.0.0.0 as it uses the name
404         # specified there as part of it's clue as to it's own name,
405         # and not to replicate to itself
406         if ol_mmr_urls is None:
407             server_port_string = "ldap://0.0.0.0:%d" % ldap_backend_extra_port
408         else:
409             server_port_string = "ldap://" + names.hostname + "." + names.dnsdomain +":%d" % ldap_backend_extra_port
410     else:
411         server_port_string = ""
412
413     # Prepare the 'result' information - the commands to return in particular
414     result.slapd_provision_command = [slapd_path]
415
416     result.slapd_provision_command.append("-F" + result.paths.olcdir)
417
418     result.slapd_provision_command.append("-h")
419
420     # copy this command so we have two version, one with -d0 and only ldapi, and one with all the listen commands
421     result.slapd_command = list(result.slapd_provision_command)
422     
423     result.slapd_provision_command.append(result.ldapi_uri)
424     result.slapd_provision_command.append("-d0")
425
426     uris = result.ldapi_uri
427     if server_port_string is not "":
428         uris = uris + " " + server_port_string
429
430     result.slapd_command.append(uris)
431
432     # Set the username - done here because Fedora DS still uses the admin DN and simple bind
433     result.credentials.set_username("samba-admin")
434     
435     # If we were just looking for crashes up to this point, it's a
436     # good time to exit before we realise we don't have OpenLDAP on
437     # this system
438     if ldap_dryrun_mode:
439         sys.exit(0)
440
441     # Finally, convert the configuration into cn=config style!
442     if not os.path.isdir(result.paths.olcdir):
443         os.makedirs(result.paths.olcdir, 0770)
444
445         retcode = subprocess.call([slapd_path, "-Ttest", "-f", result.paths.slapdconf, "-F", result.paths.olcdir], close_fds=True, shell=False)
446
447 #        We can't do this, as OpenLDAP is strange.  It gives an error
448 #        output to the above, but does the conversion sucessfully...
449 #
450 #        if retcode != 0:
451 #            raise ProvisioningError("conversion from slapd.conf to cn=config failed")
452
453         if not os.path.exists(os.path.join(result.paths.olcdir, "cn=config.ldif")):
454             raise ProvisioningError("conversion from slapd.conf to cn=config failed")
455
456         # Don't confuse the admin by leaving the slapd.conf around
457         os.remove(result.paths.slapdconf)        
458
459
460 def provision_fds_backend(result, setup_path=None, names=None,
461                           message=None, 
462                           hostname=None, ldapadminpass=None, root=None, 
463                           schema=None,
464                           ldap_backend_extra_port=None,
465                           setup_ds_path=None,
466                           slapd_path=None,
467                           nosync=False, 
468                           ldap_dryrun_mode=False,
469                           domainsid=None):
470
471     if ldap_backend_extra_port is not None:
472         serverport = "ServerPort=%d" % ldap_backend_extra_port
473     else:
474         serverport = ""
475         
476     setup_file(setup_path("fedorads.inf"), result.paths.fedoradsinf, 
477                {"ROOT": root,
478                 "HOSTNAME": hostname,
479                 "DNSDOMAIN": names.dnsdomain,
480                 "LDAPDIR": result.paths.ldapdir,
481                 "DOMAINDN": names.domaindn,
482                 "LDAPMANAGERDN": names.ldapmanagerdn,
483                 "LDAPMANAGERPASS": ldapadminpass, 
484                 "SERVERPORT": serverport})
485
486     setup_file(setup_path("fedorads-partitions.ldif"), result.paths.fedoradspartitions, 
487                {"CONFIGDN": names.configdn,
488                 "SCHEMADN": names.schemadn,
489                 "SAMBADN": names.sambadn,
490                 })
491
492     setup_file(setup_path("fedorads-sasl.ldif"), result.paths.fedoradssasl, 
493                {"SAMBADN": names.sambadn,
494                 })
495
496     setup_file(setup_path("fedorads-dna.ldif"), result.paths.fedoradsdna, 
497                {"DOMAINDN": names.domaindn,
498                 "SAMBADN": names.sambadn,
499                 "DOMAINSID": str(domainsid),
500                 })
501
502     setup_file(setup_path("fedorads-pam.ldif"), result.paths.fedoradspam)
503
504     lnkattr = schema.linked_attributes()
505
506     refint_config = data = open(setup_path("fedorads-refint-delete.ldif"), 'r').read()
507     memberof_config = ""
508     index_config = ""
509     argnum = 3
510
511     for attr in lnkattr.keys():
512         if lnkattr[attr] is not None:
513             refint_config += read_and_sub_file(setup_path("fedorads-refint-add.ldif"),
514                                                  { "ARG_NUMBER" : str(argnum) ,
515                                                    "LINK_ATTR" : attr })
516             memberof_config += read_and_sub_file(setup_path("fedorads-linked-attributes.ldif"),
517                                                  { "MEMBER_ATTR" : attr ,
518                                                    "MEMBEROF_ATTR" : lnkattr[attr] })
519             index_config += read_and_sub_file(setup_path("fedorads-index.ldif"),
520                                                  { "ATTR" : attr })
521             argnum += 1
522
523     open(result.paths.fedoradsrefint, 'w').write(refint_config)
524     open(result.paths.fedoradslinkedattributes, 'w').write(memberof_config)
525
526     attrs = ["lDAPDisplayName"]
527     res = schema.ldb.search(expression="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base=names.schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
528
529     for i in range (0, len(res)):
530         attr = res[i]["lDAPDisplayName"][0]
531
532         if attr == "objectGUID":
533             attr = "nsUniqueId"
534
535         index_config += read_and_sub_file(setup_path("fedorads-index.ldif"),
536                                              { "ATTR" : attr })
537
538     open(result.paths.fedoradsindex, 'w').write(index_config)
539
540     setup_file(setup_path("fedorads-samba.ldif"), result.paths.fedoradssamba,
541                 {"SAMBADN": names.sambadn, 
542                  "LDAPADMINPASS": ldapadminpass
543                 })
544
545     mapping = "schema-map-fedora-ds-1.0"
546     backend_schema = "99_ad.ldif"
547     
548     # Build a schema file in Fedora DS format
549     backend_schema_data = schema.ldb.convert_schema_to_openldap("fedora-ds", open(setup_path(mapping), 'r').read())
550     assert backend_schema_data is not None
551     open(os.path.join(result.paths.ldapdir, backend_schema), 'w').write(backend_schema_data)
552
553     result.credentials.set_bind_dn(names.ldapmanagerdn)
554
555     # Destory the target directory, or else setup-ds.pl will complain
556     fedora_ds_dir = os.path.join(result.paths.ldapdir, "slapd-samba4")
557     shutil.rmtree(fedora_ds_dir, True)
558
559     result.slapd_provision_command = [slapd_path, "-D", fedora_ds_dir, "-i", result.paths.slapdpid];
560     #In the 'provision' command line, stay in the foreground so we can easily kill it
561     result.slapd_provision_command.append("-d0")
562
563     #the command for the final run is the normal script
564     result.slapd_command = [os.path.join(result.paths.ldapdir, "slapd-samba4", "start-slapd")]
565
566     # If we were just looking for crashes up to this point, it's a
567     # good time to exit before we realise we don't have Fedora DS on
568     if ldap_dryrun_mode:
569         sys.exit(0)
570
571     # Try to print helpful messages when the user has not specified the path to the setup-ds tool
572     if setup_ds_path is None:
573         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\"!")
574     if not os.path.exists(setup_ds_path):
575         message (setup_ds_path)
576         raise ProvisioningError("Warning: Given Path to slapd does not exist!")
577
578     # Run the Fedora DS setup utility
579     retcode = subprocess.call([setup_ds_path, "--silent", "--file", result.paths.fedoradsinf], close_fds=True, shell=False)
580     if retcode != 0:
581         raise ProvisioningError("setup-ds failed")
582
583     # Load samba-admin
584     retcode = subprocess.call([
585         os.path.join(result.paths.ldapdir, "slapd-samba4", "ldif2db"), "-s", names.sambadn, "-i", result.paths.fedoradssamba],
586         close_fds=True, shell=False)
587     if retcode != 0:
588         raise("ldib2db failed")
589
590     # Leave a hook to do the 'post initilisation' setup
591     def fds_post_setup(self):
592         ldapi_db = Ldb(self.ldapi_uri, credentials=self.credentials)
593
594         # delete default SASL mappings
595         res = ldapi_db.search(expression="(!(cn=samba-admin mapping))", base="cn=mapping,cn=sasl,cn=config", scope=SCOPE_ONELEVEL, attrs=["dn"])
596     
597         # configure in-directory access control on Fedora DS via the aci attribute (over a direct ldapi:// socket)
598         for i in range (0, len(res)):
599             dn = str(res[i]["dn"])
600             ldapi_db.delete(dn)
601             
602             aci = """(targetattr = "*") (version 3.0;acl "full access to all by samba-admin";allow (all)(userdn = "ldap:///CN=samba-admin,%s");)""" % names.sambadn
603         
604             m = ldb.Message()
605             m["aci"] = ldb.MessageElement([aci], ldb.FLAG_MOD_REPLACE, "aci")
606
607             m.dn = ldb.Dn(1, names.domaindn)
608             ldapi_db.modify(m)
609             
610             m.dn = ldb.Dn(1, names.configdn)
611             ldapi_db.modify(m)
612             
613             m.dn = ldb.Dn(1, names.schemadn)
614             ldapi_db.modify(m)
615             
616     result.post_setup = fds_post_setup
617     
618