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