Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117780632
D732.1775247403.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
64 KB
Referenced Files
None
Subscribers
None
D732.1775247403.diff
View Options
diff --git a/.arclint b/.arclint
--- a/.arclint
+++ b/.arclint
@@ -19,11 +19,13 @@
"E131": "disabled",
"E201": "disabled",
"E202": "disabled",
+ "E221": "disabled",
"E225": "disabled",
"E231": "disabled",
"E251": "disabled",
"E261": "disabled",
"E265": "disabled",
+ "E266": "disabled",
"E302": "disabled",
"E303": "disabled",
"E402": "disabled",
diff --git a/pykolab/auth/__init__.py b/pykolab/auth/__init__.py
--- a/pykolab/auth/__init__.py
+++ b/pykolab/auth/__init__.py
@@ -49,7 +49,6 @@
Login is a simple list of username, password, service and,
optionally, the realm.
"""
-
if len(login) == 3:
# The realm has not been specified. See if we know whether or not
# to use virtual_domains, as this may be a cause for the realm not
@@ -58,12 +57,12 @@
# TODO: Insert debug statements
#if use_virtual_domains == "userid":
- #print "# Derive domain from login[0]"
+ # print "# Derive domain from login[0]"
#elif not use_virtual_domains:
- #print "# Explicitly do not user virtual domains??"
+ # print "# Explicitly do not user virtual domains??"
#else:
- ## Do use virtual domains, derive domain from login[0]
- #print "# Derive domain from login[0]"
+ # ## Do use virtual domains, derive domain from login[0]
+ # print "# Derive domain from login[0]"
if len(login[0].split('@')) > 1:
domain = login[0].split('@')[1]
@@ -86,7 +85,7 @@
back to the primary domain specified by the configuration.
"""
- log.debug(_("Called for domain %r") % (domain), level=8)
+ log.debug(_("Called for domain %r") % (domain), level=5)
if not self._auth == None:
return
@@ -99,14 +98,10 @@
section = 'kolab'
domain = conf.get('kolab', 'primary_domain')
else:
+ log.debug(_("Getting list of domains for %s ...") % (domain), level=5)
self.list_domains(domain)
section = domain
- log.debug(
- _("Using section %s and domain %s") % (section,domain),
- level=8
- )
-
if not self.domains == None and self.domains.has_key(domain):
section = self.domains[domain]
domain = self.domains[domain]
@@ -116,13 +111,6 @@
level=8
)
- log.debug(
- _("Connecting to Authentication backend for domain %s") % (
- domain
- ),
- level=8
- )
-
if not conf.has_section(section):
section = 'kolab'
@@ -142,21 +130,32 @@
level=8
)
+ _auth_mechanism = conf.get(section, 'auth_mechanism')
+
# Get the actual authentication and authorization backend.
- if conf.get(section, 'auth_mechanism') == 'ldap':
- log.debug(_("Starting LDAP..."), level=8)
+ if _auth_mechanism == 'ldap':
+ log.debug(_("Initializing LDAP..."), level=8)
from pykolab.auth import ldap
self._auth = ldap.LDAP(self.domain)
- elif conf.get(section, 'auth_mechanism') == 'sql':
+ elif _auth_mechanism == 'sql':
+ log.debug(_("Initializing SQL..."), level=8)
from pykolab.auth import sql
self._auth = sql.SQL(self.domain)
else:
- log.debug(_("Starting LDAP..."), level=8)
+ log.debug(_("Fallback to LDAP. Initializing ..."), level=5)
from pykolab.auth import ldap
self._auth = ldap.LDAP(self.domain)
+ log.debug(
+ _("Connecting to Authentication %s backend for domain %s") % (
+ _auth_mechanism,
+ domain
+ ),
+ level=5
+ )
+
self._auth.connect()
def disconnect(self, domain=None):
@@ -277,6 +276,8 @@
for secondary in secondaries:
self.domains[secondary.lower()] = primary.lower()
+ log.debug(_("List of domains for %s is: %s") % (domain, ", ".join(self.domains)), level=8)
+
return self.domains
def synchronize(self, mode=0, callback=None):
@@ -291,6 +292,9 @@
def primary_domain_for_naming_context(self, domain):
return self._auth._primary_domain_for_naming_context(domain)
+ def add_entry(self, domain, entry):
+ return self._auth._add_entry(entry)
+
def get_entry_attribute(self, domain, entry, attribute):
return self._auth.get_entry_attribute(entry, attribute)
diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py
--- a/pykolab/auth/ldap/__init__.py
+++ b/pykolab/auth/ldap/__init__.py
@@ -1525,6 +1525,26 @@
log.debug(_("bind_priv() called but already bound"), level=8)
return True
+ def _add_entry(self, entry):
+ """
+ Add generic type of entry.
+
+ Initialy created for setup-kolab to be able to add AD schema
+ by parsing Kolab AD schema ldif file
+
+ entry - dictionary, same as search results
+ """
+ self._bind()
+
+ entry_dn, entry_attrs = entry
+
+ log.debug(_("Entry DN: %s, with attributes: %s") % (entry_dn, entry_attrs), level=8)
+
+ self.ldap.add_s(
+ entry_dn,
+ entry_attrs
+ )
+
def _change_add_group(self, entry, change):
"""
An entry of type group was added.
diff --git a/pykolab/conf/__init__.py b/pykolab/conf/__init__.py
--- a/pykolab/conf/__init__.py
+++ b/pykolab/conf/__init__.py
@@ -329,7 +329,7 @@
if self.cli_args:
if len(self.cli_args) >= 1:
if hasattr(self,"command_%s" % self.cli_args[0].replace('-','_')):
- exec("self.command_%s(%r)" % (self.cli_args[0].replace('-','_'), self.cli_args[1:]))
+ exec("self.command_%s(%r)" % (self.cli_args[0].replace('-','_'), self.cli_args[1:]))
else:
print >> sys.stderr, _("No command supplied")
@@ -367,7 +367,7 @@
continue
for key in keys:
- print "%s_%s = %s" % (mode, key ,self.cfg_parser.get(mode,key))
+ print "%s_%s = %s" % (mode, key, self.cfg_parser.get(mode,key))
def read_config(self, value=None):
"""
@@ -385,7 +385,7 @@
if hasattr(self, 'cli_keywords') and hasattr(self.cli_keywords, 'config_file'):
self.cli_keywords.config_file = value
- self.defaults.config_file = value
+
self.config_file = value
def command_get(self, *args, **kw):
diff --git a/pykolab/setup/setup_ldap.py b/pykolab/setup/setup_ldap.py
--- a/pykolab/setup/setup_ldap.py
+++ b/pykolab/setup/setup_ldap.py
@@ -17,11 +17,15 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+import base64
import ldap
import ldap.modlist
+import ldap.dn
+import ldif
import os
import pwd
import shutil
+import socket
import subprocess
import tempfile
import time
@@ -35,6 +39,9 @@
from pykolab.constants import *
from pykolab.translate import _
+from StringIO import StringIO
+from jinja2 import Template
+
log = pykolab.getLogger('pykolab.setup')
conf = pykolab.getConf()
@@ -95,20 +102,461 @@
def description():
return _("Setup LDAP.")
+def get_answers():
+
+ answers = {}
+
+ if conf.fqdn:
+ answers['fqdn'] = conf.fqdn
+ answers['hostname'] = conf.fqdn.split('.')[0]
+ answers['domain'] = '.'.join(conf.fqdn.split('.')[1:])
+ else:
+ answers['fqdn'] = fqdn
+ answers['hostname'] = hostname.split('.')[0]
+ answers['domain'] = domainname
+
+ print >> sys.stderr, utils.multiline_message(
+ _("""
+ 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.
+ """)
+ )
+
+ answers['domain'] = utils.ask_question(
+ _("Domain name to use"),
+ default = answers['domain']
+ )
+
+ answers['nodotdomain'] = answers['domain'].replace('.','_')
+
+ 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.
+ """)
+ )
+
+ answers['base_dn'] = utils.ask_question(
+ _("LDAP base DN"),
+ default = utils.standard_root_dn(answers['domain'])
+ )
+
+ if conf.with_ad:
+ print >> sys.stderr, utils.multiline_message(
+ _("""
+ Please supply Active Directory Administrator bind DN.
+ This will be used to bind to Active Directory LDAP to
+ perform various administrative tasks. This user should
+ have necessary privileges in Active Directory already.
+ """)
+ )
+
+ answers['bind_dn'] = utils.ask_question(
+ _("AD Administrator bind DN"),
+ default="CN=Administrator,CN=Users,%s" % answers['base_dn']
+ )
+ elif not conf.with_ad and not conf.with_openldap:
+ # Assuming Dirsrv
+ answers['bind_dn'] = "cn=Directory Manager"
+ log.info(_("Default administrative bind dn for Directory Server: %s") % answers['bind_dn'])
+
+ # Get cn=Directory Manger password
+ if conf.directory_manager_pwd is not None:
+ # password was set with command line options
+ answers['bind_pw'] = conf.directory_manager_pwd
+ else:
+ # Ask for password
+ if conf.with_ad:
+ print >> sys.stderr, utils.multiline_message(
+ _("""
+ Please supply a password for the Active Directory Administrator user.
+ """)
+ )
+ _short_text = _("Active Directory administrator password")
+ else:
+ print >> sys.stderr, utils.multiline_message(
+ _("""
+ 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.
+ """)
+ )
+ _short_text = _("Directory Manager password")
+
+ answers['bind_pw'] = utils.ask_question(
+ _short_text,
+ default=utils.generate_password(),
+ password=True,
+ confirm=True
+ )
+
+ # Ask only if LDAP is DS
+ if not conf.with_openldap and not conf.with_ad:
+ # Get Dirsrv Admin server admin user pass
+ 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.
+ """)
+ )
+
+ answers['admin_pass'] = utils.ask_question(
+ _("Administrator password"),
+ default=utils.generate_password(),
+ password=True,
+ confirm=True
+ )
+
+
+ # Set users for DS LDAP
+ 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.
+ """)
+ )
+
+ try:
+ pw = pwd.getpwnam("dirsrv")
+ except:
+ answers['userid'] = utils.ask_question(_("User"), default="nobody")
+ answers['group'] = utils.ask_question(_("Group"), default="nobody")
+ else:
+ answers['userid'] = utils.ask_question(_("User"), default="dirsrv")
+ answers['group'] = utils.ask_question(_("Group"), default="dirsrv")
+
+ # Ask if Active Directory
+ elif conf.with_ad and not conf.with_openldap:
+ # Get answers for Active Directory setup
+ print >> sys.stderr, utils.multiline_message(
+ _("""
+ Specify basic Active Directory connection information.
+ """)
+ )
+
+ print >> sys.stderr, utils.multiline_message(
+ _("""
+ Specify LDAP tree DN for Kolab related data. Kolab specific
+ LDAP records such as Kolab domain information, special users
+ for Kolab, shared folders and resources LDAP information.
+ """)
+ )
+
+ answers['kolab_tree_dn'] = utils.ask_question(
+ _("AD LDAP tree for Kolab:"),
+ default="OU=Kolab,%s" % answers['base_dn']
+ )
+
+ answers['specialuser_base_dn'] = "OU=Special Users,%s" % answers['kolab_tree_dn']
+ answers['cyrus_admin_dn'] = "CN=Cyrus Admin,%s" % answers['specialuser_base_dn']
+ answers['service_bind_dn'] = "CN=Kolab Service,%s" % answers['specialuser_base_dn']
+ answers['domain_base_dn'] = "OU=Domains,%s" % answers['kolab_tree_dn']
+ answers['group_base_dn'] = "OU=Groups,%s" % answers['kolab_tree_dn']
+ answers['resource_base_dn'] = "OU=Resources,%s" % answers['kolab_tree_dn']
+ answers['sharedfolder_base_dn'] = "OU=Shared Folders,%s" % answers['kolab_tree_dn']
+ answers['user_base_dn'] = "CN=Users,%s" % answers['base_dn']
+ answers['kolab_user_base_dn'] = answers['user_base_dn']
+
+ print >> sys.stderr, utils.multiline_message(
+ _("""
+ Please provide Active Directory server URI. Setup will use it to load
+ Kolab schema into AD and then will configure Kolab to run with AD as
+ LDAP server. Schema can be loaded to schema master server only wherefore
+ this needs to be URI specifying AD schema master. You can change AD server
+ URI later, in kolab.conf file.
+ """)
+ )
+
+ #answers['ldap_uri'] = utils.ask_question(
+ # _("AD server URI"),
+ # default="ldap://adserver.domain:389"
+ # )
+ answers['ldap_uri'] = utils.ask_question(
+ _("AD server URI"),
+ default="ldaps://w2k16-1.ad-lab.loc:636"
+ )
+
+ print >> sys.stderr, utils.multiline_message(
+ _("""
+ 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.
+ """)
+ )
+
+ answers['cyrus_admin_password'] = utils.ask_question(
+ _("Cyrus Administrator password"),
+ default=utils.generate_password(),
+ password=True,
+ confirm=True
+ )
+
+ print >> sys.stderr, utils.multiline_message(
+ _("""
+ 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.
+ """)
+ )
+
+ answers['service_bind_pw'] = utils.ask_question(
+ _("Kolab Service password"),
+ default=utils.generate_password(),
+ password=True,
+ confirm=True
+ )
+
+ return answers
+
+def find_template(file_name=None):
+ """
+ Function to find template file.
+ """
+
+ if os.path.isfile('/etc/kolab/templates/%s' % file_name):
+ template_file = '/etc/kolab/templates/%s' % file_name
+ elif os.path.isfile('/usr/share/kolab/templates/%s' % file_name):
+ template_file = '/usr/share/kolab/templates/%s' % file_name
+ elif os.path.isfile(os.path.abspath(os.path.join(__file__, '..', '..', '..', 'share', 'templates', template ))):
+ template_file = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'share', 'templates', template ))
+ else:
+ log.error(_("Template %s not found."))
+ return None
+
+ return template_file
+
+def ad_schema_import(*args, **kwargs):
+ """
+ Function to load Kolab schema to Active Directory
+ Does checks if ldap_uri points to Schema master
+ """
+ conf.ldap_uri = kwargs['ldap_uri']
+
+ # Create LDAP connection
+ auth = Auth(kwargs['domain'])
+ auth.connect()
+ auth._auth.connect()
+ auth._auth._bind(kwargs['bind_dn'], kwargs['bind_pw'])
+
+ ad_schema_naming_context = auth._auth.get_entry_attribute("", "schemaNamingContext")
+
+ log.debug("AD Schema Naming context is %s" % ad_schema_naming_context, level=8)
+
+ # Find out AD schema master server. Only this server has writable copy of
+ # AD schema. First need to get fsmoRoleOwner attribute value.
+ ad_fsmo_attribute = auth._auth.get_entry_attribute(ad_schema_naming_context, "fSMORoleOwner")
+
+ log.debug(_("AD FSMO Role Owner entry is: %s") % ad_fsmo_attribute, level=8)
+
+ # Now get parent of fsmoRoleOwner
+ if ad_fsmo_attribute is not None:
+ ad_fsmo_dn = ldap.dn.explode_dn(ad_fsmo_attribute)
+ ad_fsmo_parent = ','.join(ad_fsmo_dn[1:])
+
+ log.debug(_("AD FSMO entry parent is: %s") % ad_fsmo_parent, level=8)
+
+ # Look for dNSHostName attribute of the parent
+ if ad_fsmo_parent is not None:
+ ad_schema_master = auth._auth.get_entry_attribute(ad_fsmo_parent, "dNSHostName")
+ log.debug(_("AD schema master server is: %s") % ad_schema_master, level=8)
+
+ (
+ _ad_protocol,
+ _ad_server,
+ _ad_port,
+ _ad_base_dn,
+ _ad_attr,
+ _ad_scope,
+ _ad_filter
+ ) = utils.parse_ldap_uri(conf.ldap_uri)
+
+ if not _ad_server == ad_schema_master:
+ log.debug(_("AD schema master %s is not the same as %s.") % (ad_schema_master, _ad_server), level=5)
+ log.error(_("Cannot install Kolab schema on AD server which is not schema master"))
+ sys.exit(1)
+
+ template_file = find_template(file_name='kolab3-ad-schema.ldif.j2')
+
+ if not template_file == None:
+ log.debug(_("Using template file %r") % (template_file), level=8)
+ fp = open(template_file, 'r')
+ template_definition = fp.read()
+ fp.close()
+
+ schema_template = Template(template_definition)
+
+ log.debug(
+ _("Successfully compiled template %r, ready to add schema to AD server") % (template_file),
+ level=8
+ )
+
+ schema_ldif = StringIO(
+ schema_template.render(ad_schema_naming_context=ad_schema_naming_context).__str__()
+ )
+
+ parser = ldif.LDIFRecordList(schema_ldif)
+ parser.parse()
+
+ # If silent install or install without asking questions
+ # when no need to ask confirmation
+ if kwargs['confirm']:
+
+ print >> sys.stderr, utils.multiline_message(
+ _("""
+ Setup is going to add Kolab schema elements to
+ Active Directory. This is ireversable operation.
+ """)
+ )
+
+ confirmed = utils.ask_confirmation(
+ _("Modify Active Directory schema?"),
+ default="y"
+ )
+
+ else:
+ # this is silent install
+ confirmed = True
+
+ if confirmed:
+ for dn, attributes in parser.all_records:
+ log.debug("Adding DN: %s" % dn, level=5)
+ try:
+ add_attributes = ldap.modlist.addModlist(attributes)
+ auth._auth.ldap.add_s(dn, add_attributes)
+ except ldap.ALREADY_EXISTS:
+ log.warning(_("Schema element already exist: %s") % dn)
+ continue
+ except ldap.NO_SUCH_ATTRIBUTE:
+ log.warning(_("Could not add %s schema element. Force update and retry.") % dn)
+ try:
+ auth._auth.set_entry_attribute("", "schemaUpdateNow", "1")
+ time.sleep(2)
+ auth._auth.ldap.add_s(dn, add_attributes)
+ except:
+ log.error(_("Failed to add %s Kolab schema element.") % dn)
+ sys.exit(1)
+ except Exception, errorMsg:
+ log.error(_("Could not add schema element: %s") % dn)
+ log.error(_("Error: %s") % errorMsg )
+ sys.exit(1)
+ else:
+ log.error(_("Kolab schema must be installed before you continue."))
+ sys.exit(1)
+
+def ldap_data_load(*args, **kwargs):
+ """
+ Function to setup LDAP tree
+ """
+ conf.ldap_uri = kwargs['ldap_uri']
+
+ # Create LDAP connection
+ auth = Auth(kwargs['domain'])
+ auth.connect()
+ auth._auth.connect()
+ auth._auth._bind(kwargs['bind_dn'], kwargs['bind_pw'])
+
+ (
+ _protocol,
+ _server,
+ _port,
+ _base_dn,
+ _attr,
+ _scope,
+ _filter
+ ) = utils.parse_ldap_uri(conf.ldap_uri)
+
+ ad_ldaps = False
+ if _protocol == 'ldap' and conf.with_ad:
+ log.info(_("Active Directory passwords cannot be set over %s protocol.") % (_protocol))
+ elif _protocol == "ldaps" and conf.with_ad:
+ ad_ldaps = True
+
+ if not kwargs['template'] == None:
+ log.debug(_("Using template file %r") % (kwargs['template']), level=8)
+ fp = open(kwargs['template'], 'r')
+ template_definition = fp.read()
+ fp.close()
+
+ _template_vars = kwargs
+ _template_vars['ad_ldaps'] = ad_ldaps
+ _template_vars['cyrus_admin_password_base64'] = base64.b64encode(
+ unicode("\"" + kwargs['cyrus_admin_password'] + "\"", "iso-8859-1").encode('utf-16-le')
+ )
+ _template_vars['service_bind_pw_base64'] = base64.b64encode(
+ unicode("\"" + kwargs['service_bind_pw'] + "\"", "iso-8859-1").encode('utf-16-le')
+ )
+
+ compiled_template = Template(template_definition)
+
+ log.debug(_("Successfully compiled template %r") % (kwargs['template']), level=1)
+
+ rendered_template = compiled_template.render(**_template_vars).__str__()
+
+ log.debug(_("Importing LDIF %s") % rendered_template, level=8)
+
+ template_ldif = StringIO(rendered_template)
+
+ parser = ldif.LDIFRecordList(template_ldif)
+ parser.parse()
+
+ for dn, attributes in parser.all_records:
+ log.debug("Adding DN: %s" % dn, level=5)
+ try:
+ add_attributes = ldap.modlist.addModlist(attributes)
+ # Do the actual synchronous add-operation to the ldapserver
+ auth._auth.ldap.add_s(dn, add_attributes)
+ except ldap.ALREADY_EXISTS:
+ log.warning(_("Object already exist: %s") % dn)
+ continue
+ except Exception, errorMsg:
+ log.error(_("Could not add object: %s") % dn)
+ log.error(_("Error: %s") % errorMsg )
+ sys.exit(1)
+
+
def execute(*args, **kw):
ask_questions = True
+ _input = {}
+
if not conf.config_file == conf.defaults.config_file:
+ log.debug(_("Using supplied config file to answer all questions"), level=5)
ask_questions = False
+ if conf.fqdn is not None:
+ log.debug(_("FQDN specified. Setting other dependend values"), level=8)
+ _input['fqdn'] = conf.fqdn
+ _input['hostname'] = conf.fqdn.split('.')[0]
+ _input['domain'] = '.'.join(conf.fqdn.split('.')[1:])
+ else:
+ log.debug(_("FQDN not specified. Derriving from defalts"), level=8)
+ _input['fqdn'] = fqdn
+ _input['hostname'] = hostname.split('.')[0]
+
+ if conf.get('kolab', 'primary_domain') is not None:
+ _input['domain'] = conf.get('kolab', 'primary_domain')
+ else:
+ _input['domain'] = domainname
+
+ if conf.get('ldap', 'base_dn') is not None:
+ _input['base_dn'] = conf.get('ldap', 'base_dn')
+ else:
+ _input['base_dn'] = utils.standard_root_dn(_input['domain'])
if conf.without_ldap:
print >> sys.stderr, _("Skipping setup of LDAP, as specified")
return
- _input = {}
-
if conf.with_openldap and not conf.with_ad:
-
+ conf.command_set('ldap', 'type', 'openldap')
conf.command_set('ldap', 'unique_attribute', 'entryuuid')
fp = open(conf.defaults.config_file, "w+")
@@ -118,14 +566,69 @@
return
elif conf.with_ad and not conf.with_openldap:
- conf.command_set('ldap', 'auth_attributes', 'samaccountname')
- conf.command_set('ldap', 'modifytimestamp_format', '%%Y%%m%%d%%H%%M%%S.0Z')
- conf.command_set('ldap', 'unique_attribute', 'userprincipalname')
+
+ if ask_questions:
+ _input = get_answers()
+ else:
+ # Get all the information from config file supplied as CLI -c param
+ _input['ldap_uri'] = conf.get('ldap', 'ldap_uri')
+ _input['bind_dn'] = conf.get('ldap', 'bind_dn')
+ _input['bind_pw'] = conf.get('ldap', 'bind_pw')
+ _input['service_bind_dn'] = conf.get('ldap', 'service_bind_dn')
+ _input['service_bind_pw'] = conf.get('ldap', 'service_bind_pw')
+ _input['user_base_dn'] = conf.get('ldap', 'user_base_dn')
+ _input['kolab_user_base_dn'] = conf.get('ldap', 'kolab_user_base_dn')
+ _input['group_base_dn'] = conf.get('ldap', 'group_base_dn')
+ _input['sharedfolder_base_dn'] = conf.get('ldap', 'sharedfolder_base_dn')
+ _input['resource_base_dn'] = conf.get('ldap', 'resource_base_dn')
+ _input['domain_base_dn'] = conf.get('ldap', 'domain_base_dn')
+ _input['cyrus_admin_password'] = conf.get('cyrus-imap', 'admin_password')
+
+ # Things which are specific to AD and are not in config file
+ _input['kolab_tree_dn'] = "OU=Kolab,%s" % _input['base_dn']
+ _input['specialuser_base_dn'] = "OU=Special Users,%s" % _input['kolab_tree_dn']
+ _input['cyrus_admin_dn'] = "CN=Cyrus Admin,%s" % _input['specialuser_base_dn']
+
+ conf.command_set('ldap', 'type', 'ad')
+ conf.command_set('ldap', 'auth_attributes', 'mail, kolabAlias, uid, samaccountname')
+ conf.command_set('ldap', 'mail_attributes', 'mail, kolabAlias')
+ conf.command_set('ldap', 'modifytimestamp_format', '%Y%m%d%H%M%S.0Z')
+ conf.command_set('ldap', 'unique_attribute', 'objectguid')
+ conf.command_set('ldap', 'sharedfolder_acl_entry_attribute', 'kolabImapACL')
+ conf.command_set('ldap', 'mailserver_attribute', 'kolabMailhost')
+ conf.command_set('ldap', 'quota_attribute', 'kolabMailquota')
# TODO: These attributes need to be checked
- conf.command_set('ldap', 'mail_attributes', 'mail')
- conf.command_set('ldap', 'mailserver_attributes', 'mailhost')
- conf.command_set('ldap', 'quota_attribute', 'mailquota')
+ conf.command_set('ldap', 'ldap_uri', _input['ldap_uri'])
+ conf.command_set('ldap', 'base_dn', _input['base_dn'])
+ conf.command_set('ldap', 'bind_dn', _input['bind_dn'])
+ conf.command_set('ldap', 'bind_pw', _input['bind_pw'])
+ conf.command_set('ldap', 'service_bind_dn', _input['service_bind_dn'])
+ conf.command_set('ldap', 'service_bind_pw', _input['service_bind_pw'])
+ conf.command_set('ldap', 'user_base_dn', _input['user_base_dn'])
+ conf.command_set('ldap', 'kolab_user_base_dn', _input['kolab_user_base_dn'])
+ conf.command_set('ldap', 'group_base_dn', _input['group_base_dn'])
+ conf.command_set('ldap', 'sharedfolder_base_dn', _input['sharedfolder_base_dn'])
+ conf.command_set('ldap', 'resource_base_dn', _input['resource_base_dn'])
+ conf.command_set('ldap', 'domain_base_dn', _input['domain_base_dn'])
+
+ conf.command_set('kolab', 'primary_domain', _input['domain'])
+ conf.command_set('cyrus-imap', 'admin_password', _input['cyrus_admin_password'])
+
+ log.error("%r" % _input)
+
+ _input['confirm'] = ask_questions
+
+ ad_schema_import(**_input)
+
+ templates = ['kolab-ad-tree.ldif.j2', 'kolab-ad-special-users.ldif.j2', 'kolab-ad-domain.ldif.j2']
+ for template in templates:
+ _input['template'] = find_template(file_name=template)
+
+ if _input['template'] is not None:
+ ldap_data_load(**_input)
+ else:
+ continue
return
@@ -139,6 +642,7 @@
sys.exit(1)
+ # This is a point where setup starts cofigure local Directory Server
# Pre-execution checks
for path, directories, files in os.walk('/etc/dirsrv/'):
for direct in directories:
@@ -155,63 +659,11 @@
sys.exit(1)
- _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.
- """)
- )
-
- _input['admin_pass'] = utils.ask_question(
- _("Administrator password"),
- default=utils.generate_password(),
- password=True,
- confirm=True
- )
-
- if conf.directory_manager_pwd is not None:
- _input['dirmgr_pass'] = conf.directory_manager_pwd
- else:
- print >> sys.stderr, utils.multiline_message(
- _("""
- 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.
- """)
- )
-
- 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")
-
+ _input = get_answers()
else:
_input['admin_pass'] = conf.get('ldap', 'bind_pw')
- _input['dirmgr_pass'] = conf.get('ldap', 'bind_pw')
+ _input['bind_pw'] = conf.get('ldap', 'bind_pw')
try:
pw = pwd.getpwnam("dirsrv")
except:
@@ -228,101 +680,33 @@
#
# TODO^2: This should be confirmed.
- if conf.fqdn:
- _input['fqdn'] = conf.fqdn
- _input['hostname'] = conf.fqdn.split('.')[0]
- _input['domain'] = '.'.join(conf.fqdn.split('.')[1:])
- else:
- _input['fqdn'] = fqdn
- _input['hostname'] = hostname.split('.')[0]
- _input['domain'] = domainname
_input['nodotdomain'] = _input['domain'].replace('.','_')
- _input['rootdn'] = utils.standard_root_dn(_input['domain'])
+ _input['ldap_uri'] = 'ldap://localhost:389/'
- if ask_questions:
- print >> sys.stderr, utils.multiline_message(
- _("""
- 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.
- """)
- )
+ # TODO: Loudly complain if the fqdn does not resolve back to this system.
- 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.
- """)
- )
+ template_file = find_template(file_name='kolab-ds-setup.inf.j2')
- _input['nodotdomain'] = _input['domain'].replace('.','_')
- _input['rootdn'] = utils.standard_root_dn(_input['domain'])
+ if template_file is not None:
+ log.debug(_("Setup Directory server using %s template") % (template_file), level=8)
- 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.
- """)
- )
+ fpr = open(template_file, 'r')
+ template_definition = fpr.read()
+ fpr.close()
- 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.
- """)
- )
+ setup_inf_template = Template(template_definition)
- # TODO: Loudly complain if the fqdn does not resolve back to this system.
+ log.debug(
+ _("Successfully compiled template %r, ready to add schema to AD server") % (template_file),
+ level=8
+ )
+
+ data = setup_inf_template.render(**_input).__str__()
- 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)
+ (fpw, filename) = tempfile.mkstemp(dir="/tmp/")
+ os.write(fpw, data)
+ os.close(fpw)
if os.path.isfile("/usr/sbin/setup-ds-admin.pl"):
setup_ds_admin = "/usr/sbin/setup-ds-admin.pl"
@@ -438,53 +822,20 @@
log.error(_("Could not configure to start on boot, the " + \
"directory server service."))
- if ask_questions:
- print >> sys.stderr, utils.multiline_message(
- _("""
- 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(
- _("""
- 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')
+ if not ask_questions:
+ _input['cyrus_admin_password'] = conf.get('cyrus-imap', 'admin_password')
+ _input['service_bind_pw'] = conf.get('ldap', 'service_bind_pw')
log.info(_("Writing out configuration to kolab.conf"))
# Write out kolab configuration
conf.command_set('kolab', 'primary_domain', _input['domain'])
- conf.command_set('ldap', 'base_dn', _input['rootdn'])
+ conf.command_set('ldap', 'ldap_uri', _input['ldap_uri'])
+ conf.command_set('ldap', 'base_dn', _input['base_dn'])
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'])
+ conf.command_set('ldap', 'bind_pw', _input['bind_pw'])
+ conf.command_set('ldap', 'service_bind_dn', 'uid=kolab-service,ou=Special Users,%s' % (_input['base_dn']))
+ conf.command_set('ldap', 'service_bind_pw', _input['service_bind_pw'])
fp = open(conf.defaults.config_file, "w+")
conf.cfg_parser.write(fp)
@@ -496,9 +847,9 @@
auth = Auth(_input['domain'])
auth.connect()
auth._auth.connect()
- auth._auth._bind(bind_dn='cn=Directory Manager', bind_pw=_input['dirmgr_pass'])
+ auth._auth._bind(bind_dn='cn=Directory Manager', bind_pw=_input['bind_pw'])
- dn = 'uid=%s,ou=Special Users,%s' % (conf.get('cyrus-imap', 'admin_login'), _input['rootdn'])
+ dn = 'uid=%s,ou=Special Users,%s' % (conf.get('cyrus-imap', 'admin_login'), _input['base_dn'])
# A dict to help build the "body" of the object
attrs = {}
@@ -507,7 +858,7 @@
attrs['givenname'] = "Cyrus"
attrs['surname'] = "Administrator"
attrs['cn'] = "Cyrus Administrator"
- attrs['userPassword'] = _input['cyrus_admin_pass']
+ attrs['userPassword'] = _input['cyrus_admin_password']
# Convert our dict to nice syntax for the add-function using modlist-module
ldif = ldap.modlist.addModlist(attrs)
@@ -515,9 +866,9 @@
# 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'])
+ conf.command_set('cyrus-imap', 'admin_password', _input['cyrus_admin_password'])
- dn = 'uid=kolab-service,ou=Special Users,%s' % (_input['rootdn'])
+ dn = 'uid=kolab-service,ou=Special Users,%s' % (_input['base_dn'])
# A dict to help build the "body" of the object
attrs = {}
@@ -526,7 +877,7 @@
attrs['givenname'] = "Kolab"
attrs['surname'] = "Service"
attrs['cn'] = "Kolab Service"
- attrs['userPassword'] = _input['kolab_service_pass']
+ attrs['userPassword'] = _input['service_bind_pw']
attrs['nslookthroughlimit'] = '-1'
attrs['nssizelimit'] = '-1'
attrs['nstimelimit'] = '-1'
@@ -538,7 +889,7 @@
# 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' % (_input['base_dn'])
# A dict to help build the "body" of the object
attrs = {}
@@ -551,7 +902,7 @@
# 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' % (_input['base_dn'])
# A dict to help build the "body" of the object
attrs = {}
@@ -572,7 +923,7 @@
attrs = {}
attrs['objectclass'] = ['top','extensibleobject']
attrs['cn'] = "kolab"
- attrs['aci'] = '(targetattr = "*") (version 3.0;acl "Kolab Services";allow (read,compare,search)(userdn = "ldap:///uid=kolab-service,ou=Special Users,%s");)' % (_input['rootdn'])
+ attrs['aci'] = '(targetattr = "*") (version 3.0;acl "Kolab Services";allow (read,compare,search)(userdn = "ldap:///uid=kolab-service,ou=Special Users,%s");)' % (_input['base_dn'])
# Convert our dict to nice syntax for the add-function using modlist-module
ldif = ldap.modlist.addModlist(attrs)
@@ -596,13 +947,13 @@
attrs['associateddomain'].pop(attrs['associateddomain'].index(_input['domain']))
attrs['associateddomain'] = [ _input['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)
+ attrs['aci'] = '(targetattr = "*") (version 3.0;acl "Read Access for %(domain)s Users";allow (read,compare,search)(userdn = "ldap:///%(base_dn)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 not _input['base_dn'] == utils.standard_root_dn(_input['domain']):
attrs['objectclass'].append('inetdomain')
- attrs['inetdomainbasedn'] = _input['rootdn']
+ attrs['inetdomainbasedn'] = _input['base_dn']
ldif = ldap.modlist.addModlist(attrs)
auth._auth.ldap.add_s(dn, ldif)
@@ -644,7 +995,7 @@
# Add kolab-admin role
log.info(_("Adding the kolab-admin role"))
- dn = "cn=kolab-admin,%s" % (_input['rootdn'])
+ dn = "cn=kolab-admin,%s" % (_input['base_dn'])
attrs = {}
attrs['description'] = "Kolab Administrator"
attrs['objectClass'] = ['top','ldapsubentry','nsroledefinition','nssimpleroledefinition','nsmanagedroledefinition']
@@ -654,8 +1005,8 @@
auth._auth.ldap.add_s(dn, ldif)
# 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") % (_input['base_dn']))
+ dn = _input['base_dn']
aci = []
if schema_error:
@@ -663,7 +1014,7 @@
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");)')
- aci.append('(targetattr = "*") (version 3.0;acl "Directory Administrators Group";allow (all)(groupdn = "ldap:///cn=Directory Administrators,%(rootdn)s" or roledn = "ldap:///cn=kolab-admin,%(rootdn)s");)' % (_input))
+ aci.append('(targetattr = "*") (version 3.0;acl "Directory Administrators Group";allow (all)(groupdn = "ldap:///cn=Directory Administrators,%(base_dn)s" or roledn = "ldap:///cn=kolab-admin,%(base_dn)s");)' % (_input))
aci.append('(targetattr="*")(version 3.0; acl "Configuration Administrators Group"; allow (all) groupdn="ldap:///cn=Configuration Administrators,ou=Groups,ou=TopologyManagement,o=NetscapeRoot";)')
aci.append('(targetattr="*")(version 3.0; acl "Configuration Administrator"; allow (all) userdn="ldap:///uid=admin,ou=Administrators,ou=TopologyManagement,o=NetscapeRoot";)')
aci.append('(targetattr = "*")(version 3.0; acl "SIE Group"; allow (all) groupdn = "ldap:///cn=slapd-%(hostname)s,cn=389 Directory Server,cn=Server Group,cn=%(fqdn)s,ou=%(domain)s,o=NetscapeRoot";)' % (_input))
diff --git a/templates/kolab-ad-domain.ldif.j2 b/templates/kolab-ad-domain.ldif.j2
new file mode 100644
--- /dev/null
+++ b/templates/kolab-ad-domain.ldif.j2
@@ -0,0 +1,13 @@
+dn: CN={{ domain }},{{ domain_base_dn }}
+changetype: add
+objectClass: top
+objectClass: domainRelatedObject
+objectClass: document
+cn: {{ domain }}
+distinguishedName: CN={{ domain }},{{ domain_base_dn }}
+instanceType: 4
+showInAdvancedViewOnly: TRUE
+name: {{ domain }}
+objectCategory: CN=document,CN=Schema,CN=Configuration,{{ base_dn }}
+associatedDomain: {{ domain }}
+
diff --git a/templates/kolab-ad-special-users.ldif.j2 b/templates/kolab-ad-special-users.ldif.j2
new file mode 100644
--- /dev/null
+++ b/templates/kolab-ad-special-users.ldif.j2
@@ -0,0 +1,50 @@
+dn: {{ cyrus_admin_dn }}
+changetype: add
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: user
+objectClass: inetOrgPerson
+cn: Cyrus Admin
+sn: Administrator
+description: User for Cyrus IMAP to connect to LDAP
+givenName: Cyrus
+distinguishedName: {{ cyrus_admin_dn }}
+displayName: Cyrus Administrator
+name: Cyrus Admin
+codePage: 0
+countryCode: 0
+sAMAccountName: cyrus-admin
+userPrincipalName: cyrus-admin@{{ domain }}
+objectCategory: CN=Person,CN=Schema,CN=Configuration,{{ base_dn }}
+uid: cyrus-admin
+{%- if ad_ldaps %}
+unicodePwd:: {{ cyrus_admin_password_base64 }}
+userAccountControl: 66048
+{% endif %}
+
+dn: {{ service_bind_dn }}
+changetype: add
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: user
+objectClass: inetOrgPerson
+cn: Kolab Service
+sn: Service
+description: User for Kolab to connect to LDAP
+givenName: Kolab
+distinguishedName: {{ service_bind_dn }}
+displayName: Kolab Service
+name: Kolab Service
+codePage: 0
+countryCode: 0
+sAMAccountName: kolab-service
+userPrincipalName: kolab-service@{{ domain }}
+objectCategory: CN=Person,CN=Schema,CN=Configuration,{{ base_dn }}
+uid: kolab-service
+{%- if ad_ldaps %}
+unicodePwd:: {{ service_bind_pw_base64 }}
+userAccountControl: 66048
+{% endif %}
+
diff --git a/templates/kolab-ad-tree.ldif.j2 b/templates/kolab-ad-tree.ldif.j2
new file mode 100644
--- /dev/null
+++ b/templates/kolab-ad-tree.ldif.j2
@@ -0,0 +1,66 @@
+dn: {{ kolab_tree_dn }}
+changetype: add
+objectClass: top
+objectClass: organizationalUnit
+ou: Kolab
+description: LDAP tree part for Kolab related data
+distinguishedName: {{ kolab_tree_dn }}
+instanceType: 4
+name: Kolab
+objectCategory: CN=Organizational-Unit,CN=Schema,CN=Configuration,{{ base_dn }}
+
+dn: {{ domain_base_dn }}
+changetype: add
+objectClass: top
+objectClass: organizationalUnit
+ou: Domains
+description: Kolab hosted domains
+distinguishedName: {{ domain_base_dn }}
+instanceType: 4
+name: Domains
+objectCategory: CN=Organizational-Unit,CN=Schema,CN=Configuration,{{ base_dn }}
+
+dn: {{ group_base_dn }}
+changetype: add
+objectClass: top
+objectClass: organizationalUnit
+ou: Groups
+description: Kolab groups
+distinguishedName: {{ group_base_dn }}
+instanceType: 4
+name: Groups
+objectCategory: CN=Organizational-Unit,CN=Schema,CN=Configuration,{{ base_dn }}
+
+dn: {{ resource_base_dn }}
+changetype: add
+objectClass: top
+objectClass: organizationalUnit
+ou: Resources
+description: Kolab resources
+distinguishedName: {{ resource_base_dn }}
+instanceType: 4
+name: Resources
+objectCategory: CN=Organizational-Unit,CN=Schema,CN=Configuration,{{ base_dn }}
+
+dn: {{ sharedfolder_base_dn }}
+changetype: add
+objectClass: top
+objectClass: organizationalUnit
+ou: Shared Folders
+description: Kolab shared folders
+distinguishedName: {{ sharedfolder_base_dn }}
+instanceType: 4
+name: Shared Folders
+objectCategory: CN=Organizational-Unit,CN=Schema,CN=Configuration,{{ base_dn }}
+
+dn: {{ specialuser_base_dn }}
+changetype: add
+objectClass: top
+objectClass: organizationalUnit
+ou: Special Users
+description: Kolab special users
+distinguishedName: ${{ specialuser_base_dn }}
+instanceType: 4
+name: Special Users
+objectCategory: CN=Organizational-Unit,CN=Schema,CN=Configuration,{{ base_dn }}
+
diff --git a/templates/kolab-ds-setup.inf.j2 b/templates/kolab-ds-setup.inf.j2
new file mode 100644
--- /dev/null
+++ b/templates/kolab-ds-setup.inf.j2
@@ -0,0 +1,24 @@
+[General]
+FullMachineName = {{ fqdn }}
+SuiteSpotUserID = {{ userid }}
+SuiteSpotGroup = {{ group }}
+AdminDomain = {{ domain }}
+ConfigDirectoryLdapURL = ldap://{{ fqdn }}:389/o=NetscapeRoot
+ConfigDirectoryAdminID = admin
+ConfigDirectoryAdminPwd = {{ admin_pass }}
+
+[slapd]
+SlapdConfigForMC = Yes
+UseExistingMC = 0
+ServerPort = 389
+ServerIdentifier = {{ hostname }}
+Suffix = {{ base_dn }}
+RootDN = cn=Directory Manager
+RootDNPwd = {{ bind_pw }}
+ds_bename = {{ nodotdomain }}
+AddSampleEntries = No
+
+[admin]
+Port = 9830
+ServerAdminID = admin
+ServerAdminPwd = {{ admin_pass }}
diff --git a/templates/kolab3-ad-schema.ldif.j2 b/templates/kolab3-ad-schema.ldif.j2
new file mode 100644
--- /dev/null
+++ b/templates/kolab3-ad-schema.ldif.j2
@@ -0,0 +1,440 @@
+dn: CN=kolabAlias,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabAlias
+distinguishedName: CN=kolabAlias,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.2.1.3
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+rangeLower: 0
+rangeUpper: 256
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabAlias
+adminDescription: RFC1274: RFC822 Mailbox
+oMSyntax: 22
+lDAPDisplayName: kolabAlias
+name: kolabAlias
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabDelegate,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabDelegate
+distinguishedName: CN=kolabDelegate,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.1.1.1.3
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+rangeUpper: 256
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabDelegate
+adminDescription:
+ Kolab user allowed to act as delegates - RFC822 Mailbox/Alias
+oMSyntax: 22
+lDAPDisplayName: kolabDelegate
+name: kolabDelegate
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabInvitationPolicy,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabInvitationPolicy
+distinguishedName:
+ CN=kolabInvitationPolicy,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.1.1.1.4
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+rangeUpper: 256
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabInvitationPolicy
+adminDescription: Defines how to respond to invitations
+oMSyntax: 22
+lDAPDisplayName: kolabInvitationPolicy
+name: kolabInvitationPolicy
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabVacationBeginDateTime,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabVacationBeginDateTime
+distinguishedName:
+ CN=kolabVacationBeginDateTime,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.1.1.1.8
+attributeSyntax: 2.5.5.11
+isSingleValued: TRUE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabVacationBeginDateTime
+adminDescription: Begin date of vacation
+oMSyntax: 24
+lDAPDisplayName: kolabVacationBeginDateTime
+name: kolabVacationBeginDateTime
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabVacationEndDateTime,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabVacationEndDateTime
+distinguishedName:
+ CN=kolabVacationEndDateTime,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.1.1.1.9
+attributeSyntax: 2.5.5.11
+isSingleValued: TRUE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabVacationEndDateTime
+adminDescription: Specifies the end of vacation time
+oMSyntax: 24
+lDAPDisplayName: kolabVacationEndDateTime
+name: kolabVacationEndDateTime
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabVacationResendInterval,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabVacationResendInterval
+distinguishedName:
+ CN=kolabVacationResendInterval,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.1.1.1.10
+attributeSyntax: 2.5.5.9
+isSingleValued: TRUE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabVacationResendInterval
+adminDescription: Vacation notice interval in days
+oMSyntax: 2
+lDAPDisplayName: kolabVacationResendInterval
+name: kolabVacationResendInterval
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabVacationAddress,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabVacationAddress
+distinguishedName:
+ CN=kolabVacationAddress,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.1.1.1.11
+attributeSyntax: 2.5.5.5
+isSingleValued: TRUE
+rangeUpper: 256
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabVacationAddress
+adminDescription: Email address for vacation to response upon
+oMSyntax: 22
+lDAPDisplayName: kolabVacationAddress
+name: kolabVacationAddress
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabForwardUCE,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabForwardUCE
+distinguishedName: CN=kolabForwardUCE,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.1.1.1.16
+attributeSyntax: 2.5.5.8
+isSingleValued: TRUE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabForwardUCE
+adminDescription: Enable forwarding of mails known as UCE
+oMSyntax: 1
+lDAPDisplayName: kolabForwardUCE
+name: kolabForwardUCE
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabAllowSMTPRecipient,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabAllowSMTPRecipient
+distinguishedName:
+ CN=kolabAllowSMTPRecipient,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.1.1.1.18
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+rangeUpper: 512
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabAllowSMTPRecipient
+adminDescription: SMTP address allowed for destination
+oMSyntax: 22
+lDAPDisplayName: kolabAllowSMTPRecipient
+name: kolabAllowSMTPRecipient
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabAllowSMTPSender,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabAllowSMTPSender
+distinguishedName:
+ CN=kolabAllowSMTPSender,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.1.1.1.43
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+rangeUpper: 512
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabAllowSMTPSender
+adminDescription: SMTP envelope sender address accepted for delivery
+oMSyntax: 22
+lDAPDisplayName: kolabAllowSMTPSender
+name: kolabAllowSMTPSender
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabFolderType,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabFolderType
+distinguishedName: CN=kolabFolderType,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.2.1.7
+attributeSyntax: 2.5.5.5
+isSingleValued: TRUE
+rangeUpper: 256
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabFolderType
+adminDescription: Type of a kolab folder
+oMSyntax: 22
+lDAPDisplayName: kolabFolderType
+name: kolabFolderType
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabTargetFolder,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabTargetFolder
+distinguishedName:
+ CN=kolabTargetFolder,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.2.1.8
+attributeSyntax: 2.5.5.12
+isSingleValued: TRUE
+rangeUpper: 512
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabTargetFolder
+adminDescription: Target for a Kolab Shared Folder delivery
+oMSyntax: 64
+lDAPDisplayName: kolabTargetFolder
+name: kolabTargetFolder
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabImapACL,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabImapACL
+distinguishedName: CN=kolabImapACL,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.2.1.651
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+rangeUpper: 256
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabImapACL
+adminDescription: Cyrus IMAP access control lists
+oMSyntax: 22
+lDAPDisplayName: kolabImapACL
+name: kolabImapACL
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabDescAttribute,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabDescAttribute
+distinguishedName:
+ CN=kolabDescAttribute,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.3.1.1
+attributeSyntax: 2.5.5.5
+isSingleValued: TRUE
+rangeUpper: 256
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabDescAttribute
+adminDescription: Descriptive attribute or parameter for a Resource
+oMSyntax: 22
+lDAPDisplayName: kolabDescAttribute
+name: kolabDescAttribute
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabMailHost,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabMailHost
+distinguishedName: CN=kolabMailHost,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.3.1.2
+attributeSyntax: 2.5.5.4
+isSingleValued: TRUE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabMailHost
+adminDescription::
+ TWFpbCBob3N0IHdoZXJlIEtvbGFiIHVzZXIsIHNoYXJlZCBmb2xkZXIgLyByZXNvdXJjZSByZXNpZG
+ VzIG9uIA==
+oMSyntax: 20
+lDAPDisplayName: kolabMailHost
+name: kolabMailHost
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabMailQuota,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: kolabMailQuota
+distinguishedName: CN=kolabMailQuota,{{ ad_schema_naming_context }}
+instanceType: 4
+attributeID: 1.3.6.1.4.1.19414.3.1.3
+attributeSyntax: 2.5.5.4
+isSingleValued: TRUE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabMailQuota
+adminDescription: Kolab mailbox quota limit.
+oMSyntax: 20
+lDAPDisplayName: kolabMailQuota
+name: kolabMailQuota
+objectCategory: CN=Attribute-Schema,{{ ad_schema_naming_context }}
+
+dn: CN=kolabSharedFolder,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: classSchema
+cn: kolabSharedFolder
+distinguishedName:
+ CN=kolabSharedFolder,{{ ad_schema_naming_context }}
+instanceType: 4
+subClassOf: top
+governsID: 1.3.6.1.4.1.19414.2.2.9
+mustContain: cn
+mayContain: owner
+mayContain: kolabImapAcl
+mayContain: kolabAlias
+mayContain: kolabAllowSMTPRecipient
+mayContain: kolabAllowSMTPSender
+mayContain: kolabDelegate
+mayContain: kolabFolderType
+mayContain: kolabMailHost
+mayContain: kolabTargetFolder
+rDNAttID: cn
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabSharedFolder
+adminDescription: Kolab public shared folder
+objectClassCategory: 3
+lDAPDisplayName: kolabSharedFolder
+name: kolabSharedFolder
+systemOnly: FALSE
+defaultSecurityDescriptor:
+ D:(A;;RPWPCRCCDCLCLOLORCWOWDSDDTDTSW;;;DA)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)
+ (A;;RPLCLORC;;;AU)
+objectCategory: CN=Class-Schema,{{ ad_schema_naming_context }}
+defaultObjectCategory:
+ CN=kolabSharedFolder,{{ ad_schema_naming_context }}
+
+dn: CN=kolabInetOrgPerson,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: classSchema
+cn: kolabInetOrgPerson
+distinguishedName:
+ CN=kolabInetOrgPerson,{{ ad_schema_naming_context }}
+instanceType: 4
+subClassOf: top
+governsID: 1.3.6.1.4.1.19414.3.2.2
+mayContain: kolabAlias
+mayContain: kolabAllowSMTPRecipient
+mayContain: kolabAllowSMTPSender
+mayContain: kolabDelegate
+mayContain: kolabForwardUCE
+mayContain: kolabInvitationPolicy
+mayContain: kolabMailHost
+mayContain: kolabMailQuota
+mayContain: kolabVacationAddress
+mayContain: kolabVacationBeginDateTime
+mayContain: kolabVacationEndDateTime
+mayContain: kolabVacationResendInterval
+rDNAttID: cn
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabInetOrgPerson
+adminDescription: Kolab Internet Organizational Person
+objectClassCategory: 3
+lDAPDisplayName: kolabInetOrgPerson
+name: kolabInetOrgPerson
+systemOnly: FALSE
+defaultSecurityDescriptor:
+ D:(A;;RPWPCRCCDCLCLOLORCWOWDSDDTDTSW;;;DA)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)
+ (A;;RPLCLORC;;;AU)
+objectCategory: CN=Class-Schema,{{ ad_schema_naming_context }}
+defaultObjectCategory:
+ CN=kolabInetOrgPerson,{{ ad_schema_naming_context }}
+
+dn: CN=kolabGroupOfUniqueNames,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: classSchema
+cn: kolabGroupOfUniqueNames
+distinguishedName:
+ CN=kolabGroupOfUniqueNames,{{ ad_schema_naming_context }}
+instanceType: 4
+subClassOf: top
+governsID: 1.3.6.1.4.1.19414.3.2.8
+mayContain: kolabAlias
+mayContain: kolabAllowSMTPRecipient
+mayContain: kolabAllowSMTPSender
+mayContain: kolabDelegate
+rDNAttID: cn
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabGroupOfUniqueNames
+adminDescription: Kolab group of names (DNs) derived from RFC2256
+objectClassCategory: 3
+lDAPDisplayName: kolabGroupOfUniqueNames
+name: kolabGroupOfUniqueNames
+systemOnly: FALSE
+defaultSecurityDescriptor:
+ D:(A;;RPWPCRCCDCLCLOLORCWOWDSDDTDTSW;;;DA)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)
+ (A;;RPLCLORC;;;AU)
+objectCategory: CN=Class-Schema,{{ ad_schema_naming_context }}
+defaultObjectCategory:
+ CN=kolabGroupOfUniqueNames,{{ ad_schema_naming_context }}
+
+dn: CN=kolabResource,{{ ad_schema_naming_context }}
+changetype: add
+objectClass: top
+objectClass: classSchema
+cn: kolabResource
+distinguishedName: CN=kolabResource,{{ ad_schema_naming_context }}
+instanceType: 4
+subClassOf: top
+governsID: 1.3.6.1.4.1.19414.3.2.9
+mayContain: description
+mayContain: kolabDescAttribute
+mayContain: kolabInvitationPolicy
+mayContain: owner
+rDNAttID: cn
+showInAdvancedViewOnly: TRUE
+adminDisplayName: kolabResource
+adminDescription: Kolab resource
+objectClassCategory: 3
+lDAPDisplayName: kolabResource
+name: kolabResource
+systemOnly: FALSE
+defaultSecurityDescriptor:
+ D:(A;;RPWPCRCCDCLCLOLORCWOWDSDDTDTSW;;;DA)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)
+ (A;;RPLCLORC;;;AU)
+objectCategory: CN=Class-Schema,{{ ad_schema_naming_context }}
+defaultObjectCategory:
+ CN=kolabResource,{{ ad_schema_naming_context }}
+-
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 3, 8:16 PM (15 h, 7 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18826282
Default Alt Text
D732.1775247403.diff (64 KB)
Attached To
Mode
D732: This is first attempt to add a AD schema import / load to kolab setup tools. The idea is that when setup-kolab is run with --with-ad it should ask questions about where the AD server is and how to connect to it. Then it should compile a AD schema...
Attached
Detach File
Event Timeline