Page MenuHomePhorge

D732.1775247403.diff
No OneTemporary

Authored By
Unknown
Size
64 KB
Referenced Files
None
Subscribers
None

D732.1775247403.diff

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

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)

Event Timeline