summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Boddie <paul@boddie.org.uk>2014-08-07 12:22:58 (GMT)
committerPaul Boddie <paul@boddie.org.uk>2014-08-07 12:22:58 (GMT)
commit9bc11d27977624991ef69040ad3d14ced9636d7d (patch)
tree89042bb845cdde8df2de809d0018979a52dacd8c
parentbf730be2c509f0f9705b83bef1ee7d49c05c3251 (diff)
downloadpykolab-9bc11d27977624991ef69040ad3d14ced9636d7d.tar.gz
Tidied LDAP setup.
Added debconf support. Added remote LDAP server support.
-rw-r--r--pykolab/setup/setup_ldap.py779
1 files changed, 474 insertions, 305 deletions
diff --git a/pykolab/setup/setup_ldap.py b/pykolab/setup/setup_ldap.py
index 04311d2..74cc828 100644
--- a/pykolab/setup/setup_ldap.py
+++ b/pykolab/setup/setup_ldap.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright 2010-2013 Kolab Systems AG (http://www.kolabsys.com)
+# Copyright 2013, 2014 Paul Boddie <paul@boddie.org.uk>
#
# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
#
@@ -17,12 +18,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+from glob import glob
+from subprocess import Popen, PIPE
import ldap
import ldap.modlist
import os
import pwd
import shutil
-import subprocess
import tempfile
import time
@@ -33,6 +35,7 @@ import pykolab
from pykolab import utils
from pykolab.auth import Auth
from pykolab.constants import *
+from pykolab.setup.services import *
from pykolab.translate import _
log = pykolab.getLogger('pykolab.setup')
@@ -61,6 +64,14 @@ def cli_options():
)
ldap_group.add_option(
+ "--choose-ldap-server",
+ dest = "choose_ldap_server",
+ action = "store_true",
+ default = False,
+ help = _("Provide a choice of LDAP server.")
+ )
+
+ ldap_group.add_option(
"--without-ldap",
dest = "without_ldap",
action = "store_true",
@@ -69,6 +80,14 @@ def cli_options():
)
ldap_group.add_option(
+ "--reset-ldap-config",
+ dest = "reset_ldap_config",
+ action = "store_true",
+ default = False,
+ help = _("Skip setting up the LDAP server, but reset Kolab's configuration for LDAP.")
+ )
+
+ ldap_group.add_option(
"--with-openldap",
dest = "with_openldap",
action = "store_true",
@@ -88,17 +107,33 @@ def description():
return _("Setup LDAP.")
def execute(*args, **kw):
- ask_questions = True
- if not conf.config_file == conf.defaults.config_file:
- ask_questions = False
+ # Signal that interaction may occur. This will involve debconf and similar
+ # system-specific mechanisms if available.
+
+ start_interaction("kolab-conf/title-ldap")
+ try:
+ _execute(*args, **kw)
+ finally:
+ stop_interaction()
+
+def _execute(*args, **kw):
+
+ # Interactive mode is enabled when dealing with an unconfigured system.
+ # Reconfiguring a configured system should not cause repetition of the
+ # questions.
+
+ unconfigured = conf.get('ldap', 'bind_pw') == "Welcome123"
+
+ ask_for_server = unconfigured or conf.choose_ldap_server
+ ask_for_credentials = unconfigured or conf.reset_ldap_config
if conf.without_ldap:
- print >> sys.stderr, _("Skipping setup of LDAP, as specified")
+ ask_question("kolab-conf/ldap-setup-skipped",
+ _("Skipping setup of LDAP, as specified.")
+ )
return
- _input = {}
-
if conf.with_openldap and not conf.with_ad:
conf.command_set('ldap', 'unique_attribute', 'entryuuid')
@@ -122,93 +157,203 @@ def execute(*args, **kw):
return
elif conf.with_ad and conf.with_openldap:
- print >> sys.stderr, utils.multiline_message(
+ ask_question("kolab-conf/ldap-system-conflict",
_("""
- You can not configure Kolab to run against OpenLDAP
+ You cannot configure Kolab to run against OpenLDAP
and Active Directory simultaneously.
""")
)
-
sys.exit(1)
- # Pre-execution checks
- for path, directories, files in os.walk('/etc/dirsrv/'):
- for direct in directories:
- if direct.startswith('slapd-'):
- print >> sys.stderr, utils.multiline_message(
+ # Where the LDAP server is to be chosen explicitly, interact with the user.
+
+ have_ldap_server = have_slapd()
+
+ ldap_uri = conf.get('ldap', 'ldap_uri')
+ ldap_uri_default = "ldap://localhost:389/"
+
+ if not conf.check_only:
+ if ask_for_server:
+ ldap_uri = ask_question("kolab-conf/ldap-server-selection",
+ _("""
+ Please indicate the LDAP server to be used by the Kolab
+ components. (If this is a remote server, no attempt will be
+ made to set up server instances or to configure services, but
+ the indicated server instance will be populated with Kolab
+ settings.)
+ """),
+ _("LDAP URI"),
+ default=(ldap_uri or ldap_uri_default)
+ ).strip()
+
+ # Remember the chosen server, used to connect and perform work.
+
+ conf.command_set('ldap', 'ldap_uri', ldap_uri)
+
+ elif not ldap_uri:
+ conf.command_set('ldap', 'ldap_uri', ldap_default)
+
+ ldap_server = ldap_uri and get_host_from_url(ldap_uri) or "localhost"
+ local_server = ldap_server == "localhost"
+
+ # Pre-execution checks.
+
+ update_directory = False
+
+ # A directory update is required if a local directory is required but
+ # missing.
+
+ if local_server:
+ update_directory = not get_slapd_configuration()
+
+ # Non-local directories may need populating.
+
+ elif not conf.check_only:
+ if ask_for_server:
+ update_directory = ask_confirmation("kolab-conf/ldap-server-population",
+ _("""
+ A different host is being used for LDAP services. Do you
+ want to populate the directory on this remote host?
+ """),
+ _("Populate remote directory"),
+ default=False
+ )
+
+ need_to_connect = local_server or ask_for_server and update_directory
+ can_connect = need_to_connect and can_connect_to_slapd(local_server)
+
+ # When only checking, use the existence of a directory to reflect the need
+ # to do any work.
+
+ if conf.check_only:
+ utils.setup_status("ldap",
+ (update_directory or need_to_connect and not can_connect) and _("needs setup") or
+ _("setup done"))
+ return
+
+ # When performing work, advise the user about the directory status.
+ # Unless the configuration is being reset or needs to be set up for the
+ # first time, no further work will be done.
+
+ if not update_directory:
+ if not conf.reset_ldap_config and not unconfigured:
+ if can_connect:
+ ask_question("kolab-conf/ldap-instances-found-available",
_("""
- It seems 389 Directory Server has an existing
- instance configured. This setup script does not
- intend to destroy or overwrite your data. Please
- make sure /etc/dirsrv/ and /var/lib/dirsrv/ are
- clean so that this setup does not have to worry.
+ It seems the directory server has an existing
+ instance configured and that this instance is
+ available using the stored credentials.
+
+ This setup script will not modify your directory.
+ If the intention is to start with a fresh
+ directory, please make sure /etc/dirsrv/ and
+ /var/lib/dirsrv/ are clean so that this setup
+ does not have to worry.
+
+ To change the Kolab configuration information,
+ should you wish to do so, run the following
+ command:
+
+ setup-kolab ldap --reset-ldap-config
""")
)
+ return
+ elif local_server:
+ ask_question("kolab-conf/ldap-instances-found-unavailable",
+ _("""
+ It seems the directory server has an existing
+ instance configured but that this instance is
+ not available using the stored credentials.
+
+ This setup script will not modify your directory.
+ If the intention is to start with a fresh
+ directory, please make sure /etc/dirsrv/ and
+ /var/lib/dirsrv/ are clean so that this setup
+ does not have to worry.
+
+ To update the Kolab configuration with
+ appropriate information, run the following
+ command:
+
+ setup-kolab ldap --reset-ldap-config
+ """)
+ )
sys.exit(1)
+ else:
+ return
+
_input = {}
- if ask_questions:
- print >> sys.stderr, utils.multiline_message(
- _("""
- Please supply a password for the LDAP administrator user
- 'admin', used to login to the graphical console of 389
- Directory server.
- """)
- )
+ # Get user credentials and details for LDAP access and administration.
- _input['admin_pass'] = utils.ask_question(
- _("Administrator password"),
- default=utils.generate_password(),
- password=True,
- confirm=True
- )
-
- print >> sys.stderr, utils.multiline_message(
+ if ask_for_credentials:
+ _input['dirmgr_pass'] = ask_question("kolab-conf/ldap-manager",
_("""
Please supply a password for the LDAP Directory Manager
user, which is the administrator user you will be using
to at least initially log in to the Web Admin, and that
Kolab uses to perform administrative tasks.
- """)
- )
-
- _input['dirmgr_pass'] = utils.ask_question(
+ """),
_("Directory Manager password"),
default=utils.generate_password(),
password=True,
confirm=True
)
- print >> sys.stderr, utils.multiline_message(
- _("""
- Please choose the system user and group the service
- should use to run under. These should be existing,
- unprivileged, local system POSIX accounts with no shell.
- """)
- )
+ # Local directory server operation.
+
+ if local_server:
+ _input['admin_pass'] = ask_question("kolab-conf/ldap-admin",
+ _("""
+ Please supply a password for the LDAP administrator user
+ 'admin', used to login to the graphical console of 389
+ Directory server.
+ """),
+ _("Administrator password"),
+ default=utils.generate_password(),
+ password=True,
+ confirm=True
+ )
- try:
- pw = pwd.getpwnam("dirsrv")
- except:
- _input['userid'] = utils.ask_question(_("User"), default="nobody")
- _input['group'] = utils.ask_question(_("Group"), default="nobody")
- else:
- _input['userid'] = utils.ask_question(_("User"), default="dirsrv")
- _input['group'] = utils.ask_question(_("Group"), default="dirsrv")
+ try:
+ pw = pwd.getpwnam("dirsrv")
+ except KeyError:
+ user_default = group_default = "nobody"
+ else:
+ user_default = group_default = "dirsrv"
+
+ _input['userid'] = ask_question("kolab-conf/dirsrv-user",
+ _("""
+ Please choose the system user the directory service should
+ use to run under. It should be an existing, unprivileged,
+ local system POSIX account with no shell.
+ """),
+ _("User"), user_default)
+
+ _input['group'] = ask_question("kolab-conf/dirsrv-group",
+ _("""
+ Please choose the system group the directory service should
+ use to run under.
+ """),
+ _("Group"), group_default)
else:
- _input['admin_pass'] = conf.get('ldap', 'bind_pw')
_input['dirmgr_pass'] = conf.get('ldap', 'bind_pw')
- try:
- pw = pwd.getpwnam("dirsrv")
- except:
- _input['userid'] = "nobody"
- _input['group'] = "nobody"
- else:
- _input['userid'] = "dirsrv"
- _input['group'] = "dirsrv"
+
+ # Local directory server operation.
+
+ if local_server:
+ _input['admin_pass'] = conf.get('ldap', 'bind_pw')
+ try:
+ pw = pwd.getpwnam("dirsrv")
+ except:
+ _input['userid'] = "nobody"
+ _input['group'] = "nobody"
+ else:
+ _input['userid'] = "dirsrv"
+ _input['group'] = "dirsrv"
# TODO: Verify the user and group exist.
@@ -217,276 +362,283 @@ def execute(*args, **kw):
#
# TODO^2: This should be confirmed.
+ domain = conf.get('kolab', 'primary_domain')
+
if conf.fqdn:
_input['fqdn'] = conf.fqdn
_input['hostname'] = conf.fqdn.split('.')[0]
- _input['domain'] = '.'.join(conf.fqdn.split('.')[1:])
+ _input['domain'] = domain or '.'.join(conf.fqdn.split('.')[1:])
+
+ # The following values are supplied by the constants module.
+
else:
_input['fqdn'] = fqdn
_input['hostname'] = hostname.split('.')[0]
- _input['domain'] = domainname
+ _input['domain'] = domain or domainname
+
_input['nodotdomain'] = _input['domain'].replace('.','_')
- _input['rootdn'] = utils.standard_root_dn(_input['domain'])
+ _input['rootdn'] = conf.get('ldap', 'base_dn') or utils.standard_root_dn(_input['domain'])
- if ask_questions:
- print >> sys.stderr, utils.multiline_message(
+ # TODO: Loudly complain if the fqdn does not resolve back to this system.
+
+ if ask_for_credentials:
+ _input['domain'] = ask_question("kolab-conf/kolab-domain-namespace",
_("""
This setup procedure plans to set up Kolab Groupware for
the following domain name space. This domain name is
obtained from the reverse DNS entry on your network
interface. Please confirm this is the appropriate domain
name space.
- """)
- )
-
- answer = utils.ask_confirmation("%s" % (_input['domain']))
-
- if not answer:
- positive_answer = False
- while not positive_answer:
- _input['domain'] = utils.ask_question(_("Domain name to use"))
- if not _input['domain'] == None and not _input['domain'] == "":
- positive_answer = True
- else:
- print >> sys.stderr, utils.multiline_message(
- _("""
- Invalid input. Please try again.
- """)
- )
+ """),
+ _("Domain name to use"),
+ "%s" % _input['domain'])
_input['nodotdomain'] = _input['domain'].replace('.','_')
- _input['rootdn'] = utils.standard_root_dn(_input['domain'])
-
- print >> sys.stderr, utils.multiline_message(
- _("""
- The standard root dn we composed for you follows. Please
- confirm this is the root dn you wish to use.
- """)
- )
-
- answer = utils.ask_confirmation("%s" % (_input['rootdn']))
-
- if not answer:
- positive_answer = False
- while not positive_answer:
- _input['rootdn'] = utils.ask_question(_("Root DN to use"))
- if not _input['rootdn'] == None and not _input['rootdn'] == "":
- positive_answer = True
- else:
- print >> sys.stderr, utils.multiline_message(
- _("""
- Invalid input. Please try again.
- """)
- )
-
- # TODO: Loudly complain if the fqdn does not resolve back to this system.
-
- data = """
-[General]
-FullMachineName = %(fqdn)s
-SuiteSpotUserID = %(userid)s
-SuiteSpotGroup = %(group)s
-AdminDomain = %(domain)s
-ConfigDirectoryLdapURL = ldap://%(fqdn)s:389/o=NetscapeRoot
-ConfigDirectoryAdminID = admin
-ConfigDirectoryAdminPwd = %(admin_pass)s
-
-[slapd]
-SlapdConfigForMC = Yes
-UseExistingMC = 0
-ServerPort = 389
-ServerIdentifier = %(hostname)s
-Suffix = %(rootdn)s
-RootDN = cn=Directory Manager
-RootDNPwd = %(dirmgr_pass)s
-ds_bename = %(nodotdomain)s
-AddSampleEntries = No
-
-[admin]
-Port = 9830
-ServerAdminID = admin
-ServerAdminPwd = %(admin_pass)s
-""" % (_input)
-
- (fp, filename) = tempfile.mkstemp(dir="/tmp/")
- os.write(fp, data)
- os.close(fp)
-
- if os.path.isfile("/usr/sbin/setup-ds-admin.pl"):
- setup_ds_admin = "/usr/sbin/setup-ds-admin.pl"
- #elif os.path.isfile("/usr/sbin/setup-ds-admin"):
- #setup_ds_admin = "/usr/sbin/setup-ds-admin"
- elif os.path.isfile("/usr/sbin/setup-ds.pl"):
- setup_ds_admin = "/usr/sbin/setup-ds.pl"
- elif os.path.isfile("/usr/sbin/setup-ds"):
- setup_ds_admin = "/usr/sbin/setup-ds"
- else:
- log.error(_("No directory server setup tool available."))
- sys.exit(1)
-
- command = [
- setup_ds_admin,
- '--debug',
- '--silent',
- '--force',
- '--file=%s' % (filename)
- ]
-
- print >> sys.stderr, utils.multiline_message(
- _("""
- Setup is now going to set up the 389 Directory Server. This
- may take a little while (during which period there is no
- output and no progress indication).
- """)
- )
-
- log.info(_("Setting up 389 Directory Server"))
- setup_389 = subprocess.Popen(
- command,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE
- )
-
- (stdoutdata, stderrdata) = setup_389.communicate()
-
- if not setup_389.returncode == 0:
- print >> sys.stderr, utils.multiline_message(
+ _input['rootdn'] = ask_question("kolab-conf/kolab-root-dn",
_("""
- An error was detected in the setup procedure for 389
- Directory Server. This setup will write out stderr and
- stdout to /var/log/kolab/setup.error.log and
- /var/log/kolab/setup.out.log respectively, before it
- exits.
- """)
+ The standard root dn we composed for you as follows.
+ Please confirm this is the root dn you wish to use.
+ """),
+ _("Root DN to use"),
+ utils.standard_root_dn(_input['domain'])
)
- fp = open('/var/log/kolab/setup.error.log', 'w')
- fp.write(stderrdata)
- fp.close()
-
- fp = open('/var/log/kolab/setup.out.log', 'w')
- fp.write(stdoutdata)
- fp.close()
-
- log.debug(_("Setup DS stdout:"), level=8)
- log.debug(stdoutdata, level=8)
-
- log.debug(_("Setup DS stderr:"), level=8)
- log.debug(stderrdata, level=8)
-
- if not setup_389.returncode == 0:
- sys.exit(1)
-
- # Find the kolab schema. It's installed as %doc in the kolab-schema package.
- # TODO: Chown nobody, nobody, chmod 440
- schema_file = None
- for root, directories, filenames in os.walk('/usr/share/doc/'):
- for filename in filenames:
- if filename.startswith('kolab') and filename.endswith('.ldif') and schema_file == None:
- schema_file = os.path.join(root,filename)
-
- if not schema_file == None:
- try:
- shutil.copy(
- schema_file,
- '/etc/dirsrv/slapd-%s/schema/99%s' % (
- _input['hostname'],
- os.path.basename(schema_file)
- )
- )
-
- schema_error = False
- except:
- log.error(_("Could not copy the LDAP extensions for Kolab"))
- schema_error = True
- else:
- log.error(_("Could not find the ldap Kolab schema file"))
- schema_error = True
-
- if os.path.isfile('/bin/systemctl'):
- subprocess.call(['/bin/systemctl', 'restart', 'dirsrv.target'])
- elif os.path.isfile('/sbin/service'):
- subprocess.call(['/sbin/service', 'dirsrv', 'restart'])
- elif os.path.isfile('/usr/sbin/service'):
- subprocess.call(['/usr/sbin/service','dirsrv','stop'])
- time.sleep(20)
- subprocess.call(['/usr/sbin/service','dirsrv','start'])
- else:
- log.error(_("Could not start the directory server service."))
-
- if os.path.isfile('/bin/systemctl'):
- subprocess.call(['/bin/systemctl', 'enable', 'dirsrv.target'])
- elif os.path.isfile('/sbin/chkconfig'):
- subprocess.call(['/sbin/chkconfig', 'dirsrv', 'on'])
- elif os.path.isfile('/usr/sbin/update-rc.d'):
- subprocess.call(['/usr/sbin/update-rc.d', 'dirsrv', 'defaults'])
- else:
- log.error(_("Could not configure to start on boot, the " + \
- "directory server service."))
-
- if ask_questions:
- print >> sys.stderr, utils.multiline_message(
+ _input['cyrus_admin_pass'] = ask_question("kolab-conf/cyrus-admin",
_("""
- Please supply a Cyrus Administrator password. This
+ Please supply a Cyrus administrator password. This
password is used by Kolab to execute administrative
tasks in Cyrus IMAP. You may also need the password
yourself to troubleshoot Cyrus IMAP and/or perform
other administrative tasks against Cyrus IMAP directly.
- """)
- )
-
- _input['cyrus_admin_pass'] = utils.ask_question(
+ """),
_("Cyrus Administrator password"),
default=utils.generate_password(),
password=True,
confirm=True
)
- print >> sys.stderr, utils.multiline_message(
+ _input['kolab_service_pass'] = ask_question("kolab-conf/ldap-kolab-service",
_("""
- Please supply a Kolab Service account password. This
+ Please supply a Kolab service account password. This
account is used by various services such as Postfix,
and Roundcube, as anonymous binds to the LDAP server
will not be allowed.
- """)
- )
-
- _input['kolab_service_pass'] = utils.ask_question(
+ """),
_("Kolab Service password"),
default=utils.generate_password(),
password=True,
confirm=True
)
- else:
- _input['cyrus_admin_pass'] = conf.get('cyrus-imap', 'admin_password')
- _input['kolab_service_pass'] = conf.get('ldap', 'service_bind_pw')
+ log.info(_("Writing out configuration to kolab.conf"))
- log.info(_("Writing out configuration to kolab.conf"))
+ # Write out kolab configuration.
- # Write out kolab configuration
+ conf.command_set('ldap', 'bind_pw', _input['dirmgr_pass'])
+ conf.command_set('ldap', 'service_bind_pw', _input['kolab_service_pass'])
+ conf.command_set('cyrus-imap', 'admin_password', _input['cyrus_admin_pass'])
+
+ conf.fqdn = fqdn
conf.command_set('kolab', 'primary_domain', _input['domain'])
conf.command_set('ldap', 'base_dn', _input['rootdn'])
conf.command_set('ldap', 'bind_dn', 'cn=Directory Manager')
- conf.command_set('ldap', 'bind_pw', _input['dirmgr_pass'])
conf.command_set('ldap', 'service_bind_dn', 'uid=kolab-service,ou=Special Users,%s' % (_input['rootdn']))
- conf.command_set('ldap', 'service_bind_pw', _input['kolab_service_pass'])
+
+ # Update the configuration file.
fp = open(conf.defaults.config_file, "w+")
conf.cfg_parser.write(fp)
fp.close()
- log.info(_("Inserting service users into LDAP."))
+ # Administer the LDAP server.
+
+ if not update_directory:
+ ask_question("kolab-conf/ldap-directory-not-changed",
+ _("""
+ No further LDAP configuration will be performed due to
+ the presence of existing directory information. Only the
+ Kolab configuration file has been updated.
+ """)
+ )
+ return
+
+ # Only where the server is local will any attempt be made to create new
+ # instances and to configure the services.
+
+ if local_server:
+ if os.path.isfile("/usr/sbin/setup-ds-admin.pl"):
+ setup_ds_admin = "/usr/sbin/setup-ds-admin.pl"
+ #elif os.path.isfile("/usr/sbin/setup-ds-admin"):
+ #setup_ds_admin = "/usr/sbin/setup-ds-admin"
+ elif os.path.isfile("/usr/sbin/setup-ds"):
+ setup_ds_admin = "/usr/sbin/setup-ds"
+ else:
+ log.error(_("No directory server setup tool available."))
+ sys.exit(1)
+
+ (fp, filename) = tempfile.mkstemp(dir="/tmp/")
+ os.write(fp, ldap_setup_data % _input)
+ os.close(fp)
+
+ command = [
+ setup_ds_admin,
+ '--debug',
+ '--silent',
+ '--force',
+ '--file=%s' % (filename)
+ ]
+
+ ask_question("kolab-conf/ldap-setup-in-progress",
+ _("""
+ Setup is now going to set up the 389 Directory Server. This
+ may take a little while (during which period there is no
+ output and no progress indication).
+ """)
+ )
+
+ log.info(_("Setting up 389 Directory Server"))
+
+ if not control_service('dirsrv', 'stop', '.target'):
+ log.error(_("Could not stop the directory server service."))
+
+ setup_389 = Popen(
+ command,
+ stdout=PIPE,
+ stderr=PIPE
+ )
+
+ (stdoutdata, stderrdata) = setup_389.communicate()
+
+ if setup_389.returncode != 0:
+ ask_question("kolab-conf/ldap-setup-error",
+ _("""
+ An error was detected in the setup procedure for 389
+ Directory Server. This setup will write out stderr and
+ stdout to /var/log/kolab/setup.error.log and
+ /var/log/kolab/setup.out.log respectively, before it
+ exits.
+ """)
+ )
+
+ fp = open('/var/log/kolab/setup.error.log', 'w')
+ fp.write(stderrdata)
+ fp.close()
- # Insert service users
- auth = Auth(_input['domain'])
+ fp = open('/var/log/kolab/setup.out.log', 'w')
+ fp.write(stdoutdata)
+ fp.close()
+
+ log.debug(_("Setup DS stdout:"), level=8)
+ log.debug(stdoutdata, level=8)
+
+ log.debug(_("Setup DS stderr:"), level=8)
+ log.debug(stderrdata, level=8)
+
+ if setup_389.returncode != 0:
+ sys.exit(1)
+
+ # Find the kolab schema. It's installed as %doc in the kolab-schema package.
+ # TODO: Chown nobody, nobody, chmod 440
+
+ schema_file = find_schema_file()
+
+ if schema_file is not None:
+ try:
+ shutil.copy(
+ schema_file,
+ '/etc/dirsrv/slapd-%s/schema/99%s' % (
+ _input['hostname'],
+ os.path.basename(schema_file)
+ )
+ )
+
+ schema_error = False
+ except:
+ log.error(_("Could not copy the LDAP extensions for Kolab"))
+ schema_error = True
+ else:
+ log.error(_("Could not find the ldap Kolab schema file"))
+ schema_error = True
+
+ if not control_service('dirsrv', 'restart', '.target'):
+ log.error(_("Could not restart the directory server service."))
+
+ # Handle any failure to restart the service.
+
+ if not ensure_slapd_service(_input['hostname']):
+ log.error(_("Directory server service not available."))
+ sys.exit(1)
+
+ if not configure_service('dirsrv', True, '.target'):
+ log.error(_("Could not configure to start on boot, the " + \
+ "directory server service."))
+
+ if not configure_service('dirsrv-admin', True):
+ log.error(_("Could not start and configure to start on boot, the " + \
+ "directory server admin service."))
+
+ # Schema population can occur on both a local server and a remote server.
+
+ if update_directory:
+ try:
+ populate_schema(_input, not schema_error)
+ except ldap.ALREADY_EXISTS:
+ log.info(_("Information already seems to exist in the directory."))
+
+def find_schema_file():
+ for kolab_dir in glob('/usr/share/doc/kolab*'):
+ for root, directories, filenames in os.walk(kolab_dir):
+ for filename in filenames:
+ if filename.startswith('kolab') and filename.endswith('.ldif'):
+ return join(root, filename)
+ return None
+
+def get_ldap_auth(domain):
+ auth = Auth(domain)
auth.connect()
auth._auth.connect()
auth._auth._bind()
+ return auth
+
+def can_connect_to_slapd(local_server=True):
+ hostname = conf.fqdn and conf.fqdn.split('.')[0] or hostname
+ if not local_server or have_slapd_process(hostname):
+ auth = get_ldap_auth(conf.get('kolab', 'primary_domain'))
+ return auth._auth.bind
+ else:
+ return False
+
+def ensure_slapd_service(hostname):
+ for retries in range(0, 3):
+ if have_slapd_process(hostname):
+ return True
+ else:
+ log.info(_("Directory service not started. Starting..."))
+ if not control_service('dirsrv', 'start', '.target'):
+ log.error(_("Could not start the directory server service."))
+ time.sleep(10)
+ else:
+ return False
+
+def populate_schema(_input, have_schema=True):
+
+ """
+ Populate the schema using the values from '_input', although the
+ configuration will be used in preference (having been set using the
+ input) to make the population process somewhat more transparent.
+ """
- dn = 'uid=%s,ou=Special Users,%s' % (conf.get('cyrus-imap', 'admin_login'), _input['rootdn'])
+ auth = get_ldap_auth(conf.get('kolab', 'primary_domain'))
+
+ # Insert service users.
+
+ log.info(_("Inserting service users into LDAP."))
+
+ dn = 'uid=%s,ou=Special Users,%s' % (
+ conf.get('cyrus-imap', 'admin_login'),
+ conf.get('ldap', 'base_dn'))
# A dict to help build the "body" of the object
attrs = {}
@@ -495,7 +647,7 @@ ServerAdminPwd = %(admin_pass)s
attrs['givenname'] = "Cyrus"
attrs['surname'] = "Administrator"
attrs['cn'] = "Cyrus Administrator"
- attrs['userPassword'] = _input['cyrus_admin_pass']
+ attrs['userPassword'] = conf.get('cyrus-imap', 'admin_password')
# Convert our dict to nice syntax for the add-function using modlist-module
ldif = ldap.modlist.addModlist(attrs)
@@ -503,9 +655,7 @@ ServerAdminPwd = %(admin_pass)s
# Do the actual synchronous add-operation to the ldapserver
auth._auth.ldap.add_s(dn, ldif)
- conf.command_set('cyrus-imap', 'admin_password', _input['cyrus_admin_pass'])
-
- dn = 'uid=kolab-service,ou=Special Users,%s' % (_input['rootdn'])
+ dn = conf.get('ldap', 'service_bind_dn')
# A dict to help build the "body" of the object
attrs = {}
@@ -514,7 +664,7 @@ ServerAdminPwd = %(admin_pass)s
attrs['givenname'] = "Kolab"
attrs['surname'] = "Service"
attrs['cn'] = "Kolab Service"
- attrs['userPassword'] = _input['kolab_service_pass']
+ attrs['userPassword'] = conf.get('ldap', 'service_bind_pw')
attrs['nslookthroughlimit'] = '-1'
attrs['nssizelimit'] = '-1'
attrs['nstimelimit'] = '-1'
@@ -526,7 +676,7 @@ ServerAdminPwd = %(admin_pass)s
# Do the actual synchronous add-operation to the ldapserver
auth._auth.ldap.add_s(dn, ldif)
- dn = 'ou=Resources,%s' % (_input['rootdn'])
+ dn = 'ou=Resources,%s' % conf.get('ldap', 'base_dn')
# A dict to help build the "body" of the object
attrs = {}
@@ -539,7 +689,7 @@ ServerAdminPwd = %(admin_pass)s
# Do the actual synchronous add-operation to the ldapserver
auth._auth.ldap.add_s(dn, ldif)
- dn = 'ou=Shared Folders,%s' % (_input['rootdn'])
+ dn = 'ou=Shared Folders,%s' % conf.get('ldap', 'base_dn')
# A dict to help build the "body" of the object
attrs = {}
@@ -570,35 +720,36 @@ ServerAdminPwd = %(admin_pass)s
auth._auth.set_entry_attribute(
dn,
'aci',
- '(targetattr = "*") (version 3.0;acl "Kolab Services";allow (read,compare,search)(userdn = "ldap:///%s");)' % ('uid=kolab-service,ou=Special Users,%s' % (_input['rootdn']))
+ '(targetattr = "*") (version 3.0;acl "Kolab Services";allow (read,compare,search)(userdn = "ldap:///%s");)' %
+ conf.get('ldap', 'service_bind_dn')
)
# TODO: Add kolab-admin role
# TODO: Assign kolab-admin admin ACLs
- log.info(_("Adding domain %s to list of domains for this deployment") % (_input['domain']))
- dn = "associateddomain=%s,cn=kolab,cn=config" % (_input['domain'])
+ log.info(_("Adding domain %s to list of domains for this deployment") % conf.get('kolab', 'primary_domain'))
+ dn = "associateddomain=%s,cn=kolab,cn=config" % conf.get('kolab', 'primary_domain')
attrs = {}
attrs['objectclass'] = ['top','domainrelatedobject']
attrs['associateddomain'] = [
- '%s' % (_input['domain']),
- '%s' % (_input['fqdn']),
+ conf.get('kolab', 'primary_domain'),
+ conf.fqdn,
'localhost.localdomain',
'localhost'
]
# De-duplicate attribute values before attempting to insert the object (#2205)
attrs['associateddomain'] = list(set(attrs['associateddomain']))
- attrs['associateddomain'].pop(attrs['associateddomain'].index(_input['domain']))
- attrs['associateddomain'] = [ _input['domain'] ] + attrs['associateddomain']
+ attrs['associateddomain'].pop(attrs['associateddomain'].index(conf.get('kolab', 'primary_domain')))
+ attrs['associateddomain'] = [ conf.get('kolab', 'primary_domain') ] + attrs['associateddomain']
attrs['aci'] = '(targetattr = "*") (version 3.0;acl "Read Access for %(domain)s Users";allow (read,compare,search)(userdn = "ldap:///%(rootdn)s??sub?(objectclass=*)");)' % (_input)
# Add inetdomainbasedn in case the configured root dn is not the same as the
# standard root dn for the domain name configured
- if not _input['rootdn'] == utils.standard_root_dn(_input['domain']):
+ if conf.get('ldap', 'base_dn') != utils.standard_root_dn(conf.get('kolab', 'primary_domain')):
attrs['objectclass'].append('inetdomain')
- attrs['inetdomainbasedn'] = _input['rootdn']
+ attrs['inetdomainbasedn'] = conf.get('ldap', 'base_dn')
ldif = ldap.modlist.addModlist(attrs)
auth._auth.ldap.add_s(dn, ldif)
@@ -640,7 +791,7 @@ ServerAdminPwd = %(admin_pass)s
# TODO: Add kolab-admin role
log.info(_("Adding the kolab-admin role"))
- dn = "cn=kolab-admin,%s" % (_input['rootdn'])
+ dn = "cn=kolab-admin,%s" % conf.get('ldap', 'base_dn')
attrs = {}
attrs['description'] = "Kolab Administrator"
attrs['objectClass'] = ['top','ldapsubentry','nsroledefinition','nssimpleroledefinition','nsmanagedroledefinition']
@@ -650,11 +801,11 @@ ServerAdminPwd = %(admin_pass)s
auth._auth.ldap.add_s(dn, ldif)
# TODO: User writeable attributes on root_dn
- log.info(_("Setting access control to %s") % (_input['rootdn']))
- dn = _input['rootdn']
+ log.info(_("Setting access control to %s") % conf.get('ldap', 'base_dn'))
+ dn = conf.get('ldap', 'base_dn')
aci = []
- if schema_error:
+ if not have_schema:
aci.append('(targetattr = "carLicense || description || displayName || facsimileTelephoneNumber || homePhone || homePostalAddress || initials || jpegPhoto || l || labeledURI || mobile || o || pager || photo || postOfficeBox || postalAddress || postalCode || preferredDeliveryMethod || preferredLanguage || registeredAddress || roomNumber || secretary || seeAlso || st || street || telephoneNumber || telexNumber || title || userCertificate || userPassword || userSMIMECertificate || x500UniqueIdentifier") (version 3.0; acl "Enable self write for common attributes"; allow (read,compare,search,write)(userdn = "ldap:///self");)')
else:
aci.append('(targetattr = "carLicense || description || displayName || facsimileTelephoneNumber || homePhone || homePostalAddress || initials || jpegPhoto || l || labeledURI || mobile || o || pager || photo || postOfficeBox || postalAddress || postalCode || preferredDeliveryMethod || preferredLanguage || registeredAddress || roomNumber || secretary || seeAlso || st || street || telephoneNumber || telexNumber || title || userCertificate || userPassword || userSMIMECertificate || x500UniqueIdentifier || kolabDelegate || kolabInvitationPolicy || kolabAllowSMTPSender") (version 3.0; acl "Enable self write for common attributes"; allow (read,compare,search,write)(userdn = "ldap:///self");)')
@@ -669,13 +820,31 @@ ServerAdminPwd = %(admin_pass)s
modlist.append((ldap.MOD_REPLACE, "aci", aci))
auth._auth.ldap.modify_s(dn, modlist)
- if os.path.isfile('/bin/systemctl'):
- subprocess.call(['/bin/systemctl', 'enable', 'dirsrv-admin.service'])
- elif os.path.isfile('/sbin/chkconfig'):
- subprocess.call(['/sbin/chkconfig', 'dirsrv-admin', 'on'])
- elif os.path.isfile('/usr/sbin/update-rc.d'):
- subprocess.call(['/usr/sbin/update-rc.d', 'dirsrv-admin', 'defaults'])
- else:
- log.error(_("Could not start and configure to start on boot, the " + \
- "directory server admin service."))
+# Data used by the above code.
+
+ldap_setup_data = """\
+[General]
+FullMachineName = %(fqdn)s
+SuiteSpotUserID = %(userid)s
+SuiteSpotGroup = %(group)s
+AdminDomain = %(domain)s
+ConfigDirectoryLdapURL = ldap://%(fqdn)s:389/o=NetscapeRoot
+ConfigDirectoryAdminID = admin
+ConfigDirectoryAdminPwd = %(admin_pass)s
+[slapd]
+SlapdConfigForMC = Yes
+UseExistingMC = 0
+ServerPort = 389
+ServerIdentifier = %(hostname)s
+Suffix = %(rootdn)s
+RootDN = cn=Directory Manager
+RootDNPwd = %(dirmgr_pass)s
+ds_bename = %(nodotdomain)s
+AddSampleEntries = No
+
+[admin]
+Port = 9830
+ServerAdminID = admin
+ServerAdminPwd = %(admin_pass)s
+"""