Example #1
0
    def test_001_two_johns(self):
        from tests.functional.user_add import user_add
        user_add("John", "Doe")
        user_add("John", "Doe")

        time.sleep(3)

        auth = Auth()
        auth.connect()

        max_tries = 20
        while max_tries > 0:
            recipient1 = auth.find_recipient('*****@*****.**')
            recipient2 = auth.find_recipient('*****@*****.**')

            if not recipient1 or not recipient2:
                time.sleep(1)
                max_tries -= 1
            else:
                break

        imap = IMAP()
        imap.connect()

        folders = imap.lm('user/[email protected]')
        self.assertEqual(len(folders), 1, "No INBOX found for first John")

        folders = imap.lm('user/[email protected]')
        self.assertEqual(len(folders), 1, "No INBOX found for second John")
Example #2
0
    def test_002_user_recipient_policy_duplicate(self):
        from tests.functional.user_add import user_add
        user = {
                'local': 'jane.doe',
                'domain': 'example.org'
            }
        user_add("Jane", "Doe")

        time.sleep(3)

        auth = Auth()
        auth.connect()
        recipient = auth.find_recipient("%(local)s@%(domain)s" % (user))
        if hasattr(self, 'assertIsInstance'):
            self.assertIsInstance(recipient, str)

        self.assertEqual(recipient, "uid=doe2,ou=People,dc=example,dc=org")

        result = wap_client.user_info(recipient)

        if not result.has_key('mailhost'):
            from tests.functional.synchronize import synchronize_once
            synchronize_once()

        result = wap_client.user_info(recipient)

        self.assertEqual(result['mail'], '*****@*****.**')
        self.assertEqual(result['alias'], ['*****@*****.**', '*****@*****.**'])
Example #3
0
 def test_002_resource_collection(self):
     auth = Auth()
     auth.connect()
     attrs = auth.get_entry_attributes(None, self.cars['dn'], ['*'])
     self.assertIn('groupofuniquenames', attrs['objectclass'])
     self.assertEqual(len(attrs['uniquemember']), 3)
     self.assertEqual(attrs['kolabinvitationpolicy'], 'ACT_ACCEPT')
def execute(*args, **kw):
    """
        List deleted mailboxes
    """

    try:
        domain = conf.cli_args.pop(0)
    except:
        domain = utils.ask_question(_("Domain"))

    imap = IMAP()
    imap.connect()

    auth = Auth()
    auth.connect()

    domains = auth.list_domains()

    folders = []
    for primary,secondaries in domains:
        if not domain == primary and not domain in secondaries:
            continue

        folders.extend(imap.lm("user/%%@%s" % (primary)))
        for secondary in secondaries:
            folders.extend(imap.lm("user/%%@%s" % (secondary)))

    print "Deleted folders:"

    for folder in folders:
        if not conf.raw:
            print imap_utf7.decode(folder)
        else:
            print folder
def execute(*args, **kw):
    """
        List deleted mailboxes
    """
    imap = IMAP()
    imap.connect()

    auth = Auth()
    auth.connect()

    domains = auth.list_domains()

    folders = []
    for domain in list(set(domains.keys())):
        folders.extend(imap.lm("DELETED/*@%s" % (domain)))

    folders.extend(imap.lm("DELETED/*"))

    print "Deleted folders:"

    for folder in folders:
        mbox_parts = imap.parse_mailfolder(folder)

        if not conf.raw:
            print "%s (Deleted at %s)" % (imap_utf7.decode(folder).encode('utf-8'), datetime.datetime.fromtimestamp(int(mbox_parts['hex_timestamp'], 16)))
        else:
            print "%s (Deleted at %s)" % (folder, datetime.datetime.fromtimestamp(int(mbox_parts['hex_timestamp'], 16)))
def execute(*args, **kw):
    """
        List deleted mailboxes
    """

    try:
        domain = conf.cli_args.pop(0)
    except:
        domain = utils.ask_question(_("Domain"))

    imap = IMAP()
    imap.connect()

    auth = Auth()
    auth.connect()

    domains = auth.list_domains()

    folders = []
    for primary,secondaries in domains:
        if not domain == primary and not domain in secondaries:
            continue

        folders.extend(imap.lm("user/%%@%s" % (primary)))
        for secondary in secondaries:
            folders.extend(imap.lm("user/%%@%s" % (secondary)))

    print "Deleted folders:"

    for folder in folders:
        if not conf.raw:
            print imap_utf7.decode(folder)
        else:
            print folder
def execute(*args, **kw):
    """
        List deleted mailboxes
    """
    imap = IMAP()
    imap.connect()

    auth = Auth()
    auth.connect()

    domains = auth.list_domains()

    folders = []
    for domain in list(set(domains.keys())):
        folders.extend(imap.lm("DELETED/*@%s" % (domain)))

    folders.extend(imap.lm("DELETED/*"))

    print "Deleted folders:"

    for folder in folders:
        utf8_folder = imap_utf7.decode(folder).encode('utf-8')
        mbox_parts = imap.parse_mailfolder(utf8_folder)
        ts = datetime.datetime.fromtimestamp(int(mbox_parts['hex_timestamp'], 16))

        if not conf.raw:
            print "%s (Deleted at %s)" % (utf8_folder, ts)
        else:
            print "%s (Deleted at %s)" % (folder, ts)
Example #8
0
    def test_002_user_recipient_policy_duplicate(self):
        from tests.functional.user_add import user_add
        user = {'local': 'jane.doe', 'domain': 'example.org'}
        user_add("Jane", "Doe")

        time.sleep(3)

        auth = Auth()
        auth.connect()
        recipient = auth.find_recipient("%(local)s@%(domain)s" % (user))
        if hasattr(self, 'assertIsInstance'):
            self.assertIsInstance(recipient, str)

        self.assertEqual(recipient, "uid=doe2,ou=People,dc=example,dc=org")

        result = wap_client.user_info(recipient)

        if 'mailhost' not in result:
            from tests.functional.synchronize import synchronize_once
            synchronize_once()

        result = wap_client.user_info(recipient)

        self.assertEqual(result['mail'], '*****@*****.**')
        self.assertEqual(result['alias'],
                         ['*****@*****.**', '*****@*****.**'])
 def test_002_resource_collection(self):
     auth = Auth()
     auth.connect()
     attrs = auth.get_entry_attributes(None, self.cars['dn'], ['*'])
     self.assertIn('groupofuniquenames', attrs['objectclass'])
     self.assertEqual(len(attrs['uniquemember']), 3)
     self.assertEqual(attrs['kolabinvitationpolicy'], 'ACT_ACCEPT')
Example #10
0
def get_resource_invitationpolicy(resource):
    """
        Get this resource's kolabinvitationpolicy configuration
    """
    global auth

    if not resource.has_key('kolabinvitationpolicy') or resource['kolabinvitationpolicy'] is None:
        if not auth:
            auth = Auth()
            auth.connect()

        # get kolabinvitationpolicy attribute from collection
        collections = auth.search_entry_by_attribute('uniquemember', resource['dn'])
        if not isinstance(collections, list):
            collections = [ (collections['dn'],collections) ]

        log.debug("Check collections %r for kolabinvitationpolicy attributes" % (collections), level=9)

        for dn,collection in collections:
            # ldap.search_entry_by_attribute() doesn't return the attributes lower-cased
            if collection.has_key('kolabInvitationPolicy'):
                collection['kolabinvitationpolicy'] = collection['kolabInvitationPolicy']

            if collection.has_key('kolabinvitationpolicy'):
                parse_kolabinvitationpolicy(collection)
                resource['kolabinvitationpolicy'] = collection['kolabinvitationpolicy']
                break

    return resource['kolabinvitationpolicy'] if resource.has_key('kolabinvitationpolicy') else None
Example #11
0
    def test_001_resource_created(self):
        auth = Auth()
        auth.connect()
        resource = auth.find_resource(self.audi['mail'])
        self.assertEqual(resource, self.audi['dn'])

        collection = auth.find_resource(self.cars['mail'])
        self.assertEqual(collection, self.cars['dn'])
Example #12
0
    def do_sync(self):
        domain_auth = {}

        pid = os.getpid()

        primary_domain = conf.get('kolab', 'primary_domain')

        while 1:
            primary_auth = Auth(primary_domain)

            log.debug(_("Listing domains..."), level=5)

            start = time.time()

            try:
                domains = primary_auth.list_domains()
            except:
                time.sleep(60)
                continue

            # domains now is a list of tuples, we want the primary_domains
            primary_domains = []
            for primary_domain, secondary_domains in domains:
                primary_domains.append(primary_domain)

            # Now we can check if any changes happened.
            added_domains = []
            removed_domains = []

            all_domains = set(primary_domains + domain_auth.keys())

            for domain in all_domains:
                if domain in domain_auth.keys() and domain in primary_domains:
                    if not domain_auth[domain].is_alive():
                        domain_auth[domain].terminate()
                        added_domains.append(domain)
                    else:
                        continue
                elif domain in domain_auth.keys():
                    removed_domains.append(domain)
                else:
                    added_domains.append(domain)

            if len(removed_domains) == 0 and len(added_domains) == 0:
                time.sleep(600)

            log.debug(
                    _("added domains: %r, removed domains: %r") % (
                            added_domains,
                            removed_domains
                        ),
                    level=8
                )

            for domain in added_domains:
                domain_auth[domain] = Process(domain)
                domain_auth[domain].start()
def execute(*args, **kw):
    """
        Synchronize or display changes
    """

    imap = IMAP()

    if not conf.connect_server == None:
        imap.connect(server=conf.connect_server)
    else:
        imap.connect()

    auth = Auth()
    auth.connect()

    domains = auth.list_domains()

    folders = imap.lm()

    imap_domains_not_domains = []

    for folder in folders:
        if len(folder.split('@')) > 1 and not folder.startswith('DELETED'):
            _folder_domain = folder.split('@')[-1]
            if not _folder_domain in list(set(domains.keys() + domains.values())):
                imap_domains_not_domains.append(folder.split('@')[-1])

    imap_domains_not_domains = list(set(imap_domains_not_domains))

    log.debug(_("Domains in IMAP not in LDAP: %r") % (imap_domains_not_domains), level=8)

    if len(imap_domains_not_domains) > 0:
        for domain in imap_domains_not_domains:
            folders = []

            folders.extend(imap.lm('shared/%%@%s' % (domain)))
            folders.extend(imap.lm('user/%%@%s' % (domain)))

            for folder in folders:
                if conf.delete:
                    if conf.dry_run:
                        if not folder.split('/')[0] == 'shared':
                            log.warning(_("No recipients for '%s' (would have deleted the mailbox if not for --dry-run)!") % ('/'.join(folder.split('/')[1:])))
                        else:
                            continue
                    else:
                        if not '/'.join(folder.split('/')[0]) == 'shared':
                            log.info(_("Deleting mailbox '%s' because it has no recipients") % (folder))
                            try:
                                imap.dm(folder)
                            except Exception, errmsg:
                                log.error(_("An error occurred removing mailbox %r: %r") % (folder, errmsg))
                        else:
                            log.info(_("Not automatically deleting shared folder '%s'") % (folder))
                else:
                    log.warning(_("No recipients for '%s' (use --delete to delete)!") % ('/'.join(folder.split('/')[1:])))
Example #14
0
def execute(*args, **kw):
    try:
        address = conf.cli_args.pop(0)
    except:
        address = utils.ask_question(_("Email Address"))

    script_to_put = conf.cli_args.pop(0)
    
    script_put_name = conf.cli_args.pop(0)

    auth = Auth()
    auth.connect()

    user = auth.find_recipient(address)

    # Get the main, default backend
    backend = conf.get('kolab', 'imap_backend')

    if len(address.split('@')) > 1:
        domain = address.split('@')[1]
    else:
        domain = conf.get('kolab', 'primary_domain')

    if conf.has_section(domain) and conf.has_option(domain, 'imap_backend'):
        backend = conf.get(domain, 'imap_backend')

    if conf.has_section(domain) and conf.has_option(domain, 'imap_uri'):
        uri = conf.get(domain, 'imap_uri')
    else:
        uri = conf.get(backend, 'uri')

    hostname = None
    port = None

    result = urlparse(uri)

    if hasattr(result, 'hostname'):
        hostname = result.hostname
    else:
        scheme = uri.split(':')[0]
        (hostname, port) = uri.split('/')[2].split(':')

    port = 4190

    # Get the credentials
    admin_login = conf.get(backend, 'admin_login')
    admin_password = conf.get(backend, 'admin_password')

    import sievelib.managesieve
 
    sieveclient = sievelib.managesieve.Client(hostname, port, False)
    sieveclient.connect(None, None, True)
    sieveclient._plain_authentication(admin_login, admin_password, address)
    sieveclient.authenticated = True

    sieveclient.putscript(script_put_name, open(script_to_put, "r").read())
    def test_002_fr_FR_user_recipient_policy(self):
        auth = Auth()
        auth.connect()
        recipient = auth.find_recipient("%(local)s@%(domain)s" % (self.user))
        if hasattr(self, 'assertIsInstance'):
            self.assertIsInstance(recipient, str)

        self.assertEqual(recipient, "uid=fuentes,ou=People,dc=example,dc=org")

        result = wap_client.user_info(recipient)

        self.assertEqual(result['mail'], '*****@*****.**')
        self.assertEqual(sorted(result['alias']), ['*****@*****.**', '*****@*****.**'])
Example #16
0
    def test_001_user_recipient_policy(self):
        auth = Auth()
        auth.connect()
        recipient = auth.find_recipient("%(local)s@%(domain)s" % (self.user))
        if hasattr(self, 'assertIsInstance'):
            self.assertIsInstance(recipient, str)

        self.assertEqual(recipient, "uid=doe,ou=People,dc=example,dc=org")

        result = wap_client.user_info(recipient)

        self.assertEqual(result['mail'], '*****@*****.**')
        self.assertEqual(result['alias'], ['*****@*****.**', '*****@*****.**'])
Example #17
0
    def test_002_fr_FR_user_recipient_policy(self):
        auth = Auth()
        auth.connect()
        recipient = auth.find_recipient("%(local)s@%(domain)s" % (self.user))
        if hasattr(self, 'assertIsInstance'):
            self.assertIsInstance(recipient, str)

        self.assertEqual(recipient, "uid=fuentes,ou=People,dc=example,dc=org")

        result = wap_client.user_info(recipient)

        self.assertEqual(result['mail'], '*****@*****.**')
        self.assertEqual(sorted(result['alias']),
                         ['*****@*****.**', '*****@*****.**'])
Example #18
0
    def test_001_user_recipient_policy(self):
        auth = Auth()
        auth.connect()
        recipient = auth.find_recipient("%(local)s@%(domain)s" % (self.user))
        if hasattr(self, 'assertIsInstance'):
            self.assertIsInstance(recipient, str)

        self.assertEqual(recipient, "uid=doe,ou=People,dc=example,dc=org")

        result = wap_client.user_info(recipient)

        self.assertEqual(result['mail'], '*****@*****.**')
        self.assertEqual(result['alias'],
                         ['*****@*****.**', '*****@*****.**'])
Example #19
0
    def test_001_user_rename(self):
        """
            Rename user "Doe, John" to "Sixpack, Joe" and verify the recipient
            policy is applied, and the IMAP INBOX folder for the user is
            renamed.
        """
        auth = Auth()
        auth.connect()
        recipient = auth.find_recipient('*****@*****.**')
        user_info = wap_client.user_info(recipient)

        if 'mailhost' not in user_info:
            from tests.functional.synchronize import synchronize_once
            synchronize_once()

        imap = IMAP()
        imap.connect()
        folders = imap.lm('user/[email protected]')
        self.assertEqual(len(folders), 1)

        auth = Auth()
        auth.connect()
        recipient = auth.find_recipient("%(local)s@%(domain)s" % (self.user))

        user_info = wap_client.user_info(recipient)
        user_info['sn'] = 'Sixpack'
        user_info['givenname'] = 'Joe'
        user_info['uid'] = 'sixpack'
        user_edit = wap_client.user_edit(recipient, user_info)

        time.sleep(2)

        print imap.lm()

        user_info = wap_client.user_info('uid=sixpack,ou=People,dc=example,dc=org')
        if not user_info['mail'] == '*****@*****.**':
            from tests.functional.synchronize import synchronize_once
            synchronize_once()
            user_info = wap_client.user_info('uid=sixpack,ou=People,dc=example,dc=org')

        self.assertEqual(user_info['mail'], '*****@*****.**')

        print imap.lm()

        folders = imap.lm('user/[email protected]')
        self.assertEqual(len(folders), 0, "INBOX for john.doe still exists")

        folders = imap.lm('user/[email protected]')
        self.assertEqual(len(folders), 1, "INBOX for joe.sixpack does not exist")
Example #20
0
class LDAPDataHandler(object):
    """
        Collector handler to provide user data from LDAP
    """

    def __init__(self, *args, **kw):
        # load pykolab conf
        self.pykolab_conf = pykolab.getConf()
        if not hasattr(self.pykolab_conf, 'defaults'):
            self.pykolab_conf.finalize_conf(fatal=False)

        self.ldap = Auth()
        self.ldap.connect()

    def register(self, callback):
        interests = {
                'GETUSERDATA': { 'callback': self.get_user_data }
            }

        callback(interests)

    def get_user_data(self, notification):
        notification = json.loads(notification)
        log.debug("GETUSERDATA for %r" % (notification), level=9)

        if notification.has_key('user'):
            try:
                user_dn = self.ldap.find_user_dn(notification['user'], True)
                log.debug("User DN for %s: %r" % (notification['user'], user_dn), level=8)
            except Exception, e:
                log.error("LDAP connection error: %r", e)
                user_dn = None

            if user_dn:
                unique_attr = self.pykolab_conf.get('ldap', 'unique_attribute', 'nsuniqueid')
                user_rec = self.ldap.get_entry_attributes(None, user_dn, [unique_attr, 'cn'])
                log.debug("User attributes: %r" % (user_rec), level=8)

                if user_rec and user_rec.has_key(unique_attr):
                    user_rec['dn'] = user_dn
                    user_rec['id'] = user_rec[unique_attr]
                    del user_rec[unique_attr]
            else:
                user_rec = None

            notification['user_data'] = user_rec

        return json.dumps(notification)
Example #21
0
    def test_001_default(self):
        from tests.functional.user_add import user_add
        user_add("John", "Doe")
        from tests.functional.synchronize import synchronize_once
        synchronize_once()

        auth = Auth()
        auth.connect()

        user = auth.find_recipient('*****@*****.**')

        user_info = wap_client.user_info(user)

        self.assertEqual(user_info['uid'], "doe")

        from tests.functional.purge_users import purge_users
        purge_users()
Example #22
0
    def __init__(self, *args, **kw):
        # load pykolab conf
        self.pykolab_conf = pykolab.getConf()
        if not hasattr(self.pykolab_conf, 'defaults'):
            self.pykolab_conf.finalize_conf(fatal=False)

        self.ldap = Auth()
        self.ldap.connect()
Example #23
0
    def test_001_default(self):
        from tests.functional.user_add import user_add
        user_add("John", "Doe")
        from tests.functional.synchronize import synchronize_once
        synchronize_once()

        auth = Auth()
        auth.connect()

        user = auth.find_recipient('*****@*****.**')

        user_info = wap_client.user_info(user)

        self.assertEqual(user_info['uid'], "doe")

        from tests.functional.purge_users import purge_users
        purge_users()
Example #24
0
def execute(*args, **kw):
    global imap, pool

    auth = Auth()
    log.debug(_("Listing domains..."), level=5)
    start_time = time.time()
    domains = auth.list_domains()
    end_time = time.time()
    log.debug(
            _("Found %d domains in %d seconds") % (
                    len(domains),
                    (end_time-start_time)
                ),
            level=8
        )

    if version.StrictVersion(sys.version[:3]) >= version.StrictVersion("2.7"):
        pool = multiprocessing.Pool(conf.threads, worker_process, (), 1)
    else:
        pool = multiprocessing.Pool(conf.threads, worker_process, ())

    for primary_domain in list(set(domains.values())):
        log.debug(_("Running for domain %s") % (primary_domain), level=8)
        auth = Auth(primary_domain)
        auth.connect(primary_domain)
        start_time = time.time()
        auth.synchronize(mode='_paged_search', callback=queue_add)
        end_time = time.time()

        log.info(_("Synchronizing users for %s took %d seconds")
                % (primary_domain, (end_time-start_time))
            )

    while not pool._taskqueue.empty():
        time.sleep(1)
def expand_mydomains():
    """
        Return a list of my domains.
    """

    auth = Auth()
    auth.connect()

    mydomains = []

    _mydomains = auth.list_domains()

    for primary, secondaries in _mydomains:
        mydomains.append(primary)
        for secondary in secondaries:
            mydomains.append(secondary)

    return mydomains
Example #26
0
    def test_003_givenname_fc_dot_surname(self):
        self.set('example.org', 'policy_uid', "'%(givenname)s'[0:1].%(surname)s")

        from tests.functional.user_add import user_add
        user_add("John", "Doe")
        from tests.functional.synchronize import synchronize_once
        synchronize_once()

        auth = Auth()
        auth.connect()

        user = auth.find_recipient('*****@*****.**')

        user_info = wap_client.user_info(user)

        self.assertEqual(user_info['uid'], "J.Doe")

        from tests.functional.purge_users import purge_users
        purge_users()
Example #27
0
    def test_003_givenname_fc_dot_surname(self):
        self.set('example.org', 'policy_uid', "'%(givenname)s'[0:1].%(surname)s")

        from tests.functional.user_add import user_add
        user_add("John", "Doe")
        from tests.functional.synchronize import synchronize_once
        synchronize_once()

        auth = Auth()
        auth.connect()

        user = auth.find_recipient('*****@*****.**')

        user_info = wap_client.user_info(user)

        self.assertEqual(user_info['uid'], "J.Doe")

        from tests.functional.purge_users import purge_users
        purge_users()
Example #28
0
def execute(*args, **kw):
    """
        List deleted mailboxes
    """
    imap = IMAP()
    imap.connect()

    auth = Auth()
    auth.connect()

    domains = auth.list_domains()

    folders = []
    for domain in domains.keys():
        print "%s: %d" % (domain, len(imap.lm("user/%%@%s" % (domain))))

    null_realm = len(imap.lm("user/%%"))

    if null_realm > 0:
        print "null: %d" % (null_realm)
def execute(*args, **kw):
    """
        List deleted mailboxes
    """
    imap = IMAP()
    imap.connect()

    auth = Auth()
    auth.connect()

    domains = auth.list_domains()

    folders = []
    for domain in domains.keys():
        print "%s: %d" % (domain,len(imap.lm("user/%%@%s" % (domain))))

    null_realm = len(imap.lm("user/%%"))

    if null_realm > 0:
        print "null: %d" % (null_realm)
Example #30
0
    def synchronize(self, domain):
        sync_interval = conf.get('kolab', 'sync_interval')

        if sync_interval == None or sync_interval == 0:
            sync_interval = 300
        else:
            sync_interval = (int)(sync_interval)

        while True:
            try:
                auth = Auth(domain)
                auth.connect(domain)
                auth.synchronize()
                time.sleep(sync_interval)
            except KeyboardInterrupt:
                break
            except Exception, errmsg:
                log.error(_("Error in process %r, terminating: %r") % (self.name, errmsg))
                import traceback
                traceback.print_exc()
                time.sleep(1)
Example #31
0
def execute(*args, **kw):
    """
        Transfer mailbox
    """

    if len(conf.cli_args) > 1:
        mailfolder = conf.cli_args.pop(0)
        target_server = conf.cli_args.pop(0)

    if len(conf.cli_args) > 0:
        target_partition = conf.cli_args.pop(0)

    imap = IMAP()
    imap.connect()

    mbox_parts = imap.parse_mailfolder(mailfolder)

    if mbox_parts['domain'] == None:
        domain = conf.get('kolab', 'primary_domain')
        user_identifier = mbox_parts['path_parts'][1]
    else:
        domain = mbox_parts['domain']
        user_identifier = "%s@%s" % (mbox_parts['path_parts'][1], mbox_parts['domain'])

    auth = Auth(domain=domain)
    auth.connect()

    user = auth.find_recipient(user_identifier)

    source_server = imap.user_mailbox_server(mailfolder)
    imap.connect(server=source_server)
    imap.imap.xfer(mailfolder, target_server)

    if not user == None and not len(user) < 1:
        auth.set_entry_attributes(domain, user, {'mailhost': target_server})
Example #32
0
def execute(*args, **kw):
    auth = Auth()
    log.debug(_("Listing domains..."), level=5)
    start_time = time.time()
    domains = auth.list_domains()
    end_time = time.time()
    log.debug(
            _("Found %d domains in %d seconds") % (
                    len(domains),
                    (end_time-start_time)
                ),
            level=8
        )

    all_folders = []

    for primary_domain,secondary_domains in domains:
        log.debug(_("Running for domain %s") % (primary_domain), level=8)
        auth.connect(primary_domain)
        start_time = time.time()
        auth.synchronize()
        end_time = time.time()

        log.info(_("Synchronizing users for %s took %d seconds")
                % (primary_domain, (end_time-start_time))
            )
Example #33
0
    def test_001_two_johns(self):
        from tests.functional.user_add import user_add
        user_add("John", "Doe")
        user_add("John", "Doe")

        time.sleep(3)

        auth = Auth()
        auth.connect()

        max_tries = 20
        while max_tries > 0:
            recipient1 = auth.find_recipient('*****@*****.**')
            recipient2 = auth.find_recipient('*****@*****.**')

            if not recipient1 or not recipient2:
                time.sleep(1)
                max_tries -= 1
            else:
                break

        imap = IMAP()
        imap.connect()

        folders = imap.lm('user/[email protected]')
        self.assertEqual(len(folders), 1, "No INBOX found for first John")

        folders = imap.lm('user/[email protected]')
        self.assertEqual(len(folders), 1, "No INBOX found for second John")
Example #34
0
    def test_001_user_rename(self):
        """
            Rename user "Doe, John" to "Sixpack, Joe" and verify the recipient
            policy is applied, and the IMAP INBOX folder for the user is
            renamed.
        """
        auth = Auth()
        auth.connect()
        recipient = auth.find_recipient('*****@*****.**')
        user_info = wap_client.user_info(recipient)

        if not user_info.has_key('mailhost'):
            from tests.functional.synchronize import synchronize_once
            synchronize_once()

        imap = IMAP()
        imap.connect()
        folders = imap.lm('user/[email protected]')
        self.assertEqual(len(folders), 1)

        auth = Auth()
        auth.connect()
        recipient = auth.find_recipient("%(local)s@%(domain)s" % (self.user))

        user_info = wap_client.user_info(recipient)
        user_info['sn'] = 'Sixpack'
        user_info['givenname'] = 'Joe'
        user_info['uid'] = 'sixpack'
        user_edit = wap_client.user_edit(recipient, user_info)

        time.sleep(2)

        print imap.lm()

        user_info = wap_client.user_info('uid=sixpack,ou=People,dc=example,dc=org')
        if not user_info['mail'] == '*****@*****.**':
            from tests.functional.synchronize import synchronize_once
            synchronize_once()
            user_info = wap_client.user_info('uid=sixpack,ou=People,dc=example,dc=org')

        self.assertEqual(user_info['mail'], '*****@*****.**')

        print imap.lm()

        folders = imap.lm('user/[email protected]')
        self.assertEqual(len(folders), 0, "INBOX for john.doe still exists")

        folders = imap.lm('user/[email protected]')
        self.assertEqual(len(folders), 1, "INBOX for joe.sixpack does not exist")
def verify_domain(domain):
    """
        Verify whether the domain is internal (mine) or external.
    """

    auth = Auth()
    auth.connect()

    domain_verified = False

    _mydomains = auth.list_domains()

    for primary, secondaries in _mydomains:
        if primary == domain:
            domain_verified = True
        elif domain in secondaries:
            domain_verified = True

    if domain_verified == None:
        domain_verified = False

    return domain_verified
Example #36
0
    def test_001_resource_created(self):
        auth = Auth()
        auth.connect()
        resource = auth.find_resource(self.audi['mail'])
        self.assertEqual(resource, self.audi['dn'])

        collection = auth.find_resource(self.cars['mail'])
        self.assertEqual(collection, self.cars['dn'])
Example #37
0
def resource_record_from_email_address(email_address):
    auth = Auth()
    auth.connect()
    resource_records = []

    log.debug(
            _("Checking if email address %r belongs to a resource (collection)") % (
                    email_address
                ),
            level=8
        )

    resource_records = auth.find_resource(email_address)

    if isinstance(resource_records, list):
        if len(resource_records) == 0:
            log.debug(
                    _("No resource (collection) records found for %r") % (
                            email_address
                        ),
                    level=9
                )

        else:
            log.debug(
                    _("Resource record(s): %r") % (resource_records),
                    level=8
                )

    elif isinstance(resource_records, basestring):
        log.debug(
                _("Resource record: %r") % (resource_records),
                level=8
            )

        resource_records = [ resource_records ]

    return resource_records
Example #38
0
def resource_record_from_email_address(email_address):
    """
        Resolves the given email address to a resource entity
    """
    global auth

    if not auth:
        auth = Auth()
        auth.connect()

    resource_records = []

    local_domains = auth.list_domains()

    if not local_domains == None:
        local_domains = list(set(local_domains.keys()))

    if not email_address.split('@')[1] in local_domains:
        return []

    log.debug(
        _("Checking if email address %r belongs to a resource (collection)") % (email_address),
        level=8
    )

    resource_records = auth.find_resource(email_address)

    if isinstance(resource_records, list):
        if len(resource_records) > 0:
            log.debug(_("Resource record(s): %r") % (resource_records), level=8)
        else:
            log.debug(_("No resource (collection) records found for %r") % (email_address), level=9)

    elif isinstance(resource_records, basestring):
        resource_records = [ resource_records ]
        log.debug(_("Resource record: %r") % (resource_records), level=8)

    return resource_records
def user_dn_from_email_address(email_address):
    """
        Resolves the given email address to a Kolab user entity
    """
    global auth

    if not auth:
        auth = Auth()
        auth.connect()

    # return cached value
    if user_dn_from_email_address.cache.has_key(email_address):
        return user_dn_from_email_address.cache[email_address]

    local_domains = auth.list_domains()

    if not local_domains == None:
        local_domains = list(set(local_domains.keys()))

    if not email_address.split('@')[1] in local_domains:
        user_dn_from_email_address.cache[email_address] = None
        return None

    log.debug(_("Checking if email address %r belongs to a local user") % (email_address), level=8)

    user_dn = auth.find_user_dn(email_address, True)

    if isinstance(user_dn, basestring):
        log.debug(_("User DN: %r") % (user_dn), level=8)
    else:
        log.debug(_("No user record(s) found for %r") % (email_address), level=9)

    # remember this lookup
    user_dn_from_email_address.cache[email_address] = user_dn

    return user_dn
Example #40
0
def heartbeat(lastrun):
    global imap

    # run archival job every hour only
    now = int(time.time())
    if lastrun == 0 or now - heartbeat._lastrun < 3600:
        return

    log.debug(_("module_resources.heartbeat(%d)") % (heartbeat._lastrun), level=8)

    # get a list of resource records from LDAP
    auth = Auth()
    auth.connect()

    resource_dns = auth.find_resource('*')

    # filter by resource_base_dn
    resource_base_dn = conf.get('ldap', 'resource_base_dn', None)
    if resource_base_dn is not None:
        resource_dns = [dn for dn in resource_dns if resource_base_dn in dn]

    if len(resource_dns) > 0:
        imap = IMAP()
        imap.connect()

        for resource_dn in resource_dns:
            resource_attrs = auth.get_entry_attributes(None, resource_dn, ['kolabtargetfolder'])
            if resource_attrs.has_key('kolabtargetfolder'):
                try:
                    expunge_resource_calendar(resource_attrs['kolabtargetfolder'])
                except Exception, e:
                    log.error(_("Expunge resource calendar for %s (%s) failed: %r") % (
                        resource_dn, resource_attrs['kolabtargetfolder'], e
                    ))

        imap.disconnect()
Example #41
0
def get_resource_owner(resource):
    """
        Get this resource's owner record
    """
    global auth

    if not auth:
        auth = Auth()
        auth.connect()

    owners = []

    if resource.has_key('owner'):
        if not isinstance(resource['owner'], list):
            owners = [ resource['owner'] ]
        else:
            owners = resource['owner']

    else:
        # get owner attribute from collection
        collections = auth.search_entry_by_attribute('uniquemember', resource['dn'])
        if not isinstance(collections, list):
            collections = [ collections ]

        for dn,collection in collections:
            if collection.has_key('owner') and isinstance(collection['owner'], list):
                owners += collection['owner']
            elif collection.has_key('owner'):
                owners.append(collection['owner'])

    for dn in owners:
        owner = auth.get_entry_attributes(None, dn, ['cn','mail','telephoneNumber'])
        if owner is not None:
            return owner

    return None
Example #42
0
def execute(*args, **kw):
    global imap, pool

    auth = Auth()

    if conf.domain == "all":
        log.debug(_("Listing domains..."), level=5)
        start_time = time.time()
        domains = auth.list_domains()
        end_time = time.time()
        log.debug(_("Found %d domains in %d seconds") %
                  (len(domains), (end_time - start_time)),
                  level=8)
    else:
        domains = {}
        domains[conf.domain] = conf.domain

    if version.StrictVersion(sys.version[:3]) >= version.StrictVersion("2.7"):
        pool = multiprocessing.Pool(conf.threads, worker_process, (), 1)
    else:
        pool = multiprocessing.Pool(conf.threads, worker_process, ())

    for primary_domain in list(set(domains.values())):
        log.debug(_("Running for domain %s") % (primary_domain), level=8)
        auth = Auth(primary_domain)
        auth.connect(primary_domain)
        start_time = time.time()
        auth.synchronize(mode='_paged_search', callback=queue_add)
        end_time = time.time()

        log.info(
            _("Synchronizing users for %s took %d seconds") %
            (primary_domain, (end_time - start_time)))

    while not pool._taskqueue.empty():
        time.sleep(1)
Example #43
0
def execute(*args, **kw):
    """
        Transfer mailbox
    """

    if len(conf.cli_args) > 1:
        mailfolder = conf.cli_args.pop(0)
        target_server = conf.cli_args.pop(0)

    if len(conf.cli_args) > 0:
        target_partition = conf.cli_args.pop(0)

    imap = IMAP()
    imap.connect()

    mbox_parts = imap.parse_mailfolder(mailfolder)

    if mbox_parts['domain'] == None:
        domain = conf.get('kolab', 'primary_domain')
        user_identifier = mbox_parts['path_parts'][1]
    else:
        domain = mbox_parts['domain']
        user_identifier = "%s@%s" % (mbox_parts['path_parts'][1],
                                     mbox_parts['domain'])

    auth = Auth(domain=domain)
    auth.connect()

    user = auth.find_recipient(user_identifier)

    source_server = imap.user_mailbox_server(mailfolder)
    imap.connect(server=source_server)
    imap.imap.xfer(mailfolder, target_server)

    if not user == None and not len(user) < 1:
        auth.set_entry_attributes(domain, user, {'mailhost': target_server})
Example #44
0
    def synchronize(self, domain):
        log.debug(_("Synchronizing for domain %s") % (domain), level=8)
        sync_interval = conf.get('kolab', 'sync_interval')

        if sync_interval is None or sync_interval == 0:
            sync_interval = 300
        else:
            sync_interval = (int)(sync_interval)

        while True:
            try:
                auth = Auth(domain)
                auth.connect(domain)
                auth.synchronize()
                time.sleep(sync_interval)
            except KeyboardInterrupt:
                break
            except Exception, errmsg:
                log.error(
                    _("Error in process %r, terminating:\n\t%r") %
                    (self.name, errmsg))
                import traceback
                traceback.print_exc()
                time.sleep(1)
Example #45
0
from pykolab.auth import Auth
from pykolab.constants import KOLAB_LIB_PATH
from pykolab import telemetry
from pykolab.translate import _

# TODO: Figure out how to make our logger do some syslogging as well.
log = pykolab.getLogger('pykolab.parse_telemetry')

# TODO: Removing the stdout handler would mean one can no longer test by
# means of manual execution in debug mode.
#log.remove_stdout_handler()

conf = pykolab.getConf()
conf.finalize_conf()

auth = Auth()

db = telemetry.init_db()

while True:
    try:
        log_file = conf.cli_args.pop(0)
    except:
        # TODO: More verbose failing or parse all in /var/lib/imap/log/ or
        # options?
        break

    telemetry_log = telemetry.TelemetryLog(log_file)

telemetry.expire_sessions()
Example #46
0
    def user_mailbox_create(self, mailbox_base_name, server=None):
        """
            Create a user mailbox.

            Returns the full path to the new mailbox folder.
        """
        # TODO: Whether or not to lowercase the mailbox name is really up to the
        # IMAP server setting username_tolower (normalize_uid, lmtp_downcase_rcpt).

        self.connect()

        if not mailbox_base_name == mailbox_base_name.lower():
            log.warning(_("Downcasing mailbox name %r") % (mailbox_base_name))
            mailbox_base_name = mailbox_base_name.lower()

        folder_name = "user%s%s" % (self.get_separator(), mailbox_base_name)
        log.info(_("Creating new mailbox for user %s") %(mailbox_base_name))

        max_tries = 10
        success = False
        while not success and max_tries > 0:
            success = self.create_folder(folder_name, server)
            if not success:
                self.disconnect()
                max_tries -= 1
                time.sleep(1)
                self.connect()

        if not success:
            log.error(_("Could not create the mailbox for user %s, aborting." % (mailbox_base_name)))
            return False

        # In a Cyrus IMAP Murder topology, wait for the murder to have settled
        if self.imap_murder():
            self.disconnect()
            self.connect()

            created = False
            last_log = time.time()
            while not created:
                created = self.has_folder(folder_name)
                if not created:
                    if time.time() - last_log > 5:
                        log.info(_("Waiting for the Cyrus IMAP Murder to settle..."))
                        last_log = time.time()

                    time.sleep(0.5)

        _additional_folders = None

        if not hasattr(self, 'domain'):
            self.domain = None

        if self.domain == None and len(mailbox_base_name.split('@')) > 1:
            self.domain = mailbox_base_name.split('@')[1]

        if not self.domain == None:
            if conf.has_option(self.domain, "autocreate_folders"):
                _additional_folders = conf.get_raw(
                        self.domain,
                        "autocreate_folders"
                    )

            else:
                from pykolab.auth import Auth
                auth = Auth()
                auth.connect()

                domains = auth.list_domains(self.domain)

                auth.disconnect()

                if len(domains.keys()) > 0:
                    if domains.has_key(self.domain):
                        primary = domains[self.domain]

                        if conf.has_option(primary, "autocreate_folders"):
                            _additional_folders = conf.get_raw(
                                    primary,
                                    "autocreate_folders"
                                )

        if _additional_folders == None:
            if conf.has_option('kolab', "autocreate_folders"):
                _additional_folders = conf.get_raw(
                        'kolab',
                        "autocreate_folders"
                    )

        additional_folders = conf.plugins.exec_hook(
                "create_user_folders",
                kw={
                        'folder': folder_name,
                        'additional_folders': _additional_folders
                    }
            )

        if not additional_folders == None:
            self.user_mailbox_create_additional_folders(
                    mailbox_base_name,
                    additional_folders
                )

        if not self.domain == None:
            if conf.has_option(self.domain, "sieve_mgmt"):
                sieve_mgmt_enabled = conf.get(self.domain, 'sieve_mgmt')
                if utils.true_or_false(sieve_mgmt_enabled):
                    conf.plugins.exec_hook(
                            'sieve_mgmt_refresh',
                            kw={
                                    'user': mailbox_base_name
                                }
                        )

        return folder_name
Example #47
0
def execute(*args, **kw):

    try:
        primary_rcpt_address = conf.cli_args.pop(0)
        try:
            secondary_rcpt_address = conf.cli_args.pop(0)
        except:
            print >> sys.stderr, _("Specify the (new) alias address")
            sys.exit(1)
    except:
        print >> sys.stderr, _("Specify the existing recipient address")
        sys.exit(1)

    if len(primary_rcpt_address.split('@')) > 1:
        primary_rcpt_domain = primary_rcpt_address.split('@')[-1]
    else:
        primary_rcpt_domain = conf.get('kolab', 'primary_domain')

    auth = Auth(domain=primary_rcpt_domain)

    domains = auth.list_domains()

    #print domains

    if len(secondary_rcpt_address.split('@')) > 1:
        secondary_rcpt_domain = secondary_rcpt_address.split('@')[-1]
    else:
        secondary_rcpt_domain = conf.get('kolab', 'primary_domain')

    # Check if either is in fact a domain
    if not primary_rcpt_domain.lower() in domains.keys():
        print >> sys.stderr, _("Domain %r is not a local domain") % (
            primary_rcpt_domain)
        sys.exit(1)

    if not secondary_rcpt_domain.lower() in domains.keys():
        print >> sys.stderr, _("Domain %r is not a local domain") % (
            secondary_rcpt_domain)
        sys.exit(1)

    if not primary_rcpt_domain == secondary_rcpt_domain:
        if not domains[primary_rcpt_domain] == domains[secondary_rcpt_domain]:
            print >> sys.stderr, _(
                "Primary and secondary domain do not have the same parent domain"
            )
            sys.exit(1)

    primary_recipient_dn = auth.find_recipient(primary_rcpt_address)

    if primary_recipient_dn == [] or len(primary_recipient_dn) == 0:
        print >> sys.stderr, _("No such recipient %r") % (primary_rcpt_address)
        sys.exit(1)

    secondary_recipient_dn = auth.find_recipient(secondary_rcpt_address)

    if not secondary_recipient_dn == [] and not len(
            secondary_recipient_dn) == 0:
        print >> sys.stderr, _("Recipient for alias %r already exists") % (
            secondary_rcpt_address)
        sys.exit(1)

    rcpt_attrs = conf.get_list('ldap', 'mail_attributes')

    primary_rcpt_attr = rcpt_attrs[0]

    if len(rcpt_attrs) >= 2:
        secondary_rcpt_attr = rcpt_attrs[1]
    else:
        print >> sys.stderr, _("Environment is not configured for " + \
            "users to hold secondary mail attributes")

        sys.exit(1)

    primary_recipient = auth.get_entry_attributes(primary_rcpt_domain,
                                                  primary_recipient_dn,
                                                  rcpt_attrs)

    if not primary_recipient.has_key(primary_rcpt_attr):
        print >> sys.stderr, _(
            "Recipient %r is not the primary recipient for address %r") % (
                primary_recipient, primary_rcpt_address)
        sys.exit(1)

    if not primary_recipient.has_key(secondary_rcpt_attr):
        auth.set_entry_attributes(
            primary_rcpt_domain, primary_recipient_dn,
            {secondary_rcpt_attr: [secondary_rcpt_address]})
    else:
        if isinstance(primary_recipient[secondary_rcpt_attr], basestring):
            new_secondary_rcpt_attrs = [
                primary_recipient[secondary_rcpt_attr], secondary_rcpt_address
            ]

        else:
            new_secondary_rcpt_attrs = \
                    primary_recipient[secondary_rcpt_attr] + \
                    [ secondary_rcpt_address ]

        auth.set_entry_attributes(
            primary_rcpt_domain, primary_recipient_dn,
            {secondary_rcpt_attr: new_secondary_rcpt_attrs})
Example #48
0
def execute(*args, **kw):
    try:
        address = conf.cli_args.pop(0)
    except:
        address = utils.ask_question(_("Email Address"))

    auth = Auth()
    auth.connect()

    user = auth.find_recipient(address)

    # Get the main, default backend
    backend = conf.get('kolab', 'imap_backend')

    if len(address.split('@')) > 1:
        domain = address.split('@')[1]
    else:
        domain = conf.get('kolab', 'primary_domain')

    if conf.has_section(domain) and conf.has_option(domain, 'imap_backend'):
        backend = conf.get(domain, 'imap_backend')

    if conf.has_section(domain) and conf.has_option(domain, 'imap_uri'):
        uri = conf.get(domain, 'imap_uri')
    else:
        uri = conf.get(backend, 'uri')

    hostname = None
    port = None

    result = urlparse(uri)

    if hasattr(result, 'hostname'):
        hostname = result.hostname
    else:
        scheme = uri.split(':')[0]
        (hostname, port) = uri.split('/')[2].split(':')

    port = 4190

    # Get the credentials
    admin_login = conf.get(backend, 'admin_login')
    admin_password = conf.get(backend, 'admin_password')

    import sievelib.managesieve

    sieveclient = sievelib.managesieve.Client(hostname, port, True)
    sieveclient.connect(None, None, True)
    sieveclient._plain_authentication(admin_login, admin_password, address)
    sieveclient.authenticated = True

    active, scripts = sieveclient.listscripts()

    print "%s (active)" % (active)

    _all_scripts = [active] + scripts
    _used_scripts = [active]
    _included_scripts = []

    _a_script = sieveclient.getscript(active)

    print _a_script

    import sievelib.parser

    _a_parser = sievelib.parser.Parser(debug=True)
    _a_parsed = _a_parser.parse(_a_script)

    #print "%r" % (_a_parsed)

    if not _a_parsed:
        print _a_parser.error

    print "%r" % (_a_parser.result)

    for _a_command in _a_parser.result:
        print _a_command.name, _a_command.arguments
        if len(_a_command.children) > 0:
            for _a_child in _a_command.children:
                print "  ", _a_child.name, _a_child.arguments

        if _a_command.name == "include":
            if _a_command.arguments["script"].strip('"') in scripts:
                print "OK"
                _used_scripts.append(_a_command.arguments["script"].strip('"'))
            else:
                print "Not OK"

    for script in scripts:
        print script
Example #49
0
def execute(*args, **kw):
    if not os.path.isdir(mybasepath):
        os.makedirs(mybasepath)

    for stage in ['incoming', 'ACCEPT', 'REJECT', 'HOLD', 'DEFER' ]:
        if not os.path.isdir(os.path.join(mybasepath, stage)):
            os.makedirs(os.path.join(mybasepath, stage))

    log.debug(_("Resource Management called for %r, %r") % (args, kw), level=9)

    auth = Auth()
    auth.connect()

    imap = IMAP()
    imap.connect()

    # TODO: Test for correct call.
    filepath = args[0]

    if kw.has_key('stage'):
        log.debug(
                _("Issuing callback after processing to stage %s") % (
                        kw['stage']
                    ),
                level=8
            )

        log.debug(_("Testing cb_action_%s()") % (kw['stage']), level=8)
        if hasattr(modules, 'cb_action_%s' % (kw['stage'])):
            log.debug(
                    _("Attempting to execute cb_action_%s()") % (kw['stage']),
                    level=8
                )

            exec(
                    'modules.cb_action_%s(%r, %r)' % (
                            kw['stage'],
                            'resources',
                            filepath
                        )
                )

            return
    else:
        # Move to incoming
        new_filepath = os.path.join(
                mybasepath,
                'incoming',
                os.path.basename(filepath)
            )

        if not filepath == new_filepath:
            log.debug("Renaming %r to %r" % (filepath, new_filepath))
            os.rename(filepath, new_filepath)
            filepath = new_filepath

    _message = json.load(open(filepath, 'r'))
    log.debug("Loaded message %r" % (_message), level=9)
    message = message_from_string(_message['data'])
    recipients = _message['to']

    any_itips = False
    any_resources = False
    possibly_any_resources = True

    # An iTip message may contain multiple events. Later on, test if the message
    # is an iTip message by checking the length of this list.
    itip_events = itip_events_from_message(message)

    if not len(itip_events) > 0:
        log.info(
                _("Message is not an iTip message or does not contain any " + \
                    "(valid) iTip.")
            )

    else:
        any_itips = True

        log.debug(
                _("iTip events attached to this message contain the " + \
                    "following information: %r") % (itip_events),
                level=9
            )

    if any_itips:
        # See if any iTip actually allocates a resource.
        if len([x['resources'] for x in itip_events if x.has_key('resources')]) == 0:
            if len([x['attendees'] for x in itip_events if x.has_key('attendees')]) == 0:
                possibly_any_resources = False
        else:
            possibly_any_resources = False

    if possibly_any_resources:
        for recipient in recipients:
            if not len(resource_record_from_email_address(recipient)) == 0:
                any_resources = True

    if any_resources:
        if not any_itips:
            log.debug(_("Not an iTip message, but sent to resource nonetheless. Reject message"), level=5)
            reject(filepath)
            return
        else:
            # Continue. Resources and iTips. We like.
            pass
    else:
        if not any_itips:
            log.debug(_("No itips, no resources, pass along"), level=5)
            accept(filepath)
            return
        else:
            log.debug(_("iTips, but no resources, pass along"), level=5)
            accept(filepath)
            return

    # A simple list of merely resource entry IDs that hold any relevance to the
    # iTip events
    resource_records = resource_records_from_itip_events(itip_events)

    # Get the resource details, which includes details on the IMAP folder
    resources = {}
    for resource_record in list(set(resource_records)):
        # Get the attributes for the record
        # See if it is a resource collection
        #   If it is, expand to individual resources
        #   If it is not, ...
        resource_attrs = auth.get_entry_attributes(None, resource_record, ['*'])
        if not 'kolabsharedfolder' in [x.lower() for x in resource_attrs['objectclass']]:
            if resource_attrs.has_key('uniquemember'):
                resources[resource_record] = resource_attrs
                for uniquemember in resource_attrs['uniquemember']:
                    resource_attrs = auth.get_entry_attributes(
                            None,
                            uniquemember,
                            ['*']
                        )

                    if 'kolabsharedfolder' in [x.lower() for x in resource_attrs['objectclass']]:
                        resources[uniquemember] = resource_attrs
                        resources[uniquemember]['memberof'] = resource_record
        else:
            resources[resource_record] = resource_attrs

    log.debug(_("Resources: %r") % (resources), level=8)

    # For each resource, determine if any of the events in question is in
    # conflict.
    #
    # Store the (first) conflicting event(s) alongside the resource information.
    start = time.time()

    for resource in resources.keys():
        if not resources[resource].has_key('kolabtargetfolder'):
            continue

        mailbox = resources[resource]['kolabtargetfolder']

        resources[resource]['conflict'] = False
        resources[resource]['conflicting_events'] = []

        log.debug(
                _("Checking events in resource folder %r") % (mailbox),
                level=8
            )

        try:
            imap.imap.m.select(mailbox)
        except:
            log.error(_("Mailbox for resource %r doesn't exist") % (resource))
            continue

        typ, data = imap.imap.m.search(None, 'ALL')

        num_messages = len(data[0].split())

        for num in data[0].split():
            # For efficiency, makes the routine non-deterministic
            if resources[resource]['conflict']:
                continue

            log.debug(
                    _("Fetching message UID %r from folder %r") % (num, mailbox),
                    level=9
                )

            typ, data = imap.imap.m.fetch(num, '(RFC822)')

            event_message = message_from_string(data[0][1])

            if event_message.is_multipart():
                for part in event_message.walk():
                    if part.get_content_type() == "application/calendar+xml":
                        payload = part.get_payload(decode=True)
                        event = pykolab.xml.event_from_string(payload)

                        for itip in itip_events:
                            _es = to_dt(event.get_start())
                            _is = to_dt(itip['start'].dt)

                            _ee = to_dt(event.get_end())
                            _ie = to_dt(itip['end'].dt)

                            if _es < _is:
                                if _es <= _ie:
                                    if _ee <= _is:
                                        conflict = False
                                    else:
                                        conflict = True
                                else:
                                    conflict = True
                            elif _es == _is:
                                conflict = True
                            else: # _es > _is
                                if _es <= _ie:
                                    conflict = True
                                else:
                                    conflict = False

                            if conflict:
                                log.info(
                                        _("Event %r conflicts with event " + \
                                            "%r") % (
                                                itip['xml'].get_uid(),
                                                event.get_uid()
                                            )
                                    )

                                resources[resource]['conflicting_events'].append(event)
                                resources[resource]['conflict'] = True

    end = time.time()

    log.debug(
            _("start: %r, end: %r, total: %r, messages: %r") % (
                    start, end, (end-start), num_messages
                ),
            level=1
        )

    for resource in resources.keys():
        log.debug(_("Polling for resource %r") % (resource), level=9)

        if not resources.has_key(resource):
            log.debug(
                    _("Resource %r has been popped from the list") % (resource),
                    level=9
                )

            continue

        if not resources[resource].has_key('conflicting_events'):
            log.debug(_("Resource is a collection"), level=9)
            continue

        if len(resources[resource]['conflicting_events']) > 0:
            # This is the event being conflicted with!
            for itip_event in itip_events:
                # Now we have the event that was conflicting
                if resources[resource]['mail'] in [a.get_email() for a in itip_event['xml'].get_attendees()]:
                    itip_event['xml'].set_attendee_participant_status(
                            [a for a in itip_event['xml'].get_attendees() if a.get_email() == resources[resource]['mail']][0],
                            "DECLINED"
                        )

                    send_response(resources[resource]['mail'], itip_events)
                    # TODO: Accept the message to the other attendees

                else:
                    # This must have been a resource collection originally.
                    # We have inserted the reference to the original resource
                    # record in 'memberof'.
                    if resources[resource].has_key('memberof'):
                        original_resource = resources[resources[resource]['memberof']]

                        _target_resource = resources[original_resource['uniquemember'][random.randint(0,(len(original_resource['uniquemember'])-1))]]

                        # unset all
                        for _r in original_resource['uniquemember']:
                            del resources[_r]

                    if original_resource['mail'] in [a.get_email() for a in itip_event['xml'].get_attendees()]:
                        itip_event['xml'].set_attendee_participant_status(
                                [a for a in itip_event['xml'].get_attendees() if a.get_email() == original_resource['mail']][0],
                                "DECLINED"
                            )

                        send_response(original_resource['mail'], itip_events)
                        # TODO: Accept the message to the other attendees

        else:
            # No conflicts, go accept
            for itip_event in itip_events:
                if resources[resource]['mail'] in [a.get_email() for a in itip_event['xml'].get_attendees()]:
                    itip_event['xml'].set_attendee_participant_status(
                            [a for a in itip_event['xml'].get_attendees() if a.get_email() == resources[resource]['mail']][0],
                            "ACCEPTED"
                        )

                    log.debug(
                            _("Adding event to %r") % (
                                    resources[resource]['kolabtargetfolder']
                                ),
                            level=9
                        )

                    imap.imap.m.setacl(resources[resource]['kolabtargetfolder'], "cyrus-admin", "lrswipkxtecda")
                    imap.imap.m.append(
                            resources[resource]['kolabtargetfolder'],
                            None,
                            None,
                            itip_event['xml'].to_message().as_string()
                        )

                    send_response(resources[resource]['mail'], itip_event)

                else:
                    # This must have been a resource collection originally.
                    # We have inserted the reference to the original resource
                    # record in 'memberof'.
                    if resources[resource].has_key('memberof'):
                        original_resource = resources[resources[resource]['memberof']]

                        # Randomly selects a target resource from the resource
                        # collection.
                        _target_resource = resources[original_resource['uniquemember'][random.randint(0,(len(original_resource['uniquemember'])-1))]]

                        # Remove all resources from the collection.
                        for _r in original_resource['uniquemember']:
                            del resources[_r]

                    if original_resource['mail'] in [a.get_email() for a in itip_event['xml'].get_attendees()]:
                        #
                        # Delegate:
                        #
                        # - delegator: the original resource collection
                        # - delegatee: the target resource
                        #

                        itip_event['xml'].delegate(
                                original_resource['mail'],
                                _target_resource['mail']
                            )

                        itip_event['xml'].set_attendee_participant_status(
                                [a for a in itip_event['xml'].get_attendees() if a.get_email() == _target_resource['mail']][0],
                                "ACCEPTED"
                            )

                        log.debug(
                                _("Adding event to %r") % (
                                        _target_resource['kolabtargetfolder']
                                    ),
                                level=9
                            )

                        # TODO: The Cyrus IMAP (or Dovecot) Administrator login
                        # name comes from configuration.
                        imap.imap.m.setacl(_target_resource['kolabtargetfolder'], "cyrus-admin", "lrswipkxtecda")
                        imap.imap.m.append(
                                _target_resource['kolabtargetfolder'],
                                None,
                                None,
                                itip_event['xml'].to_message().as_string()
                            )

                        send_response(original_resource['mail'], itip_event)

    # Disconnect IMAP or we lock the mailbox almost constantly
    imap.disconnect()
    del imap

    os.unlink(filepath)
Example #50
0
def execute(*args, **kw):
    ask_questions = True

    if not conf.config_file == conf.defaults.config_file:
        ask_questions = False

    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', 'unique_attribute', 'entryuuid')

        fp = open(conf.defaults.config_file, "w+")
        conf.cfg_parser.write(fp)
        fp.close()

        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')

        # 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')

        return

    elif conf.with_ad and conf.with_openldap:
        print >> sys.stderr, utils.multiline_message(
            _("""
                        You can not configure Kolab to run against OpenLDAP
                        and Active Directory simultaneously.
                    """))

        sys.exit(1)

    # Pre-execution checks
    for path, directories, files in os.walk('/etc/dirsrv/'):
        for direct in directories:
            if direct.startswith('slapd-'):
                print >> sys.stderr, utils.multiline_message(
                    _("""
                                It seems 389 Directory Server has an existing
                                instance configured. This setup script does not
                                intend to destroy or overwrite your data. Please
                                make sure /etc/dirsrv/ and /var/lib/dirsrv/ are
                                clean so that this setup does not have to worry.
                            """))

                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")

    else:
        _input['admin_pass'] = conf.get('ldap', 'bind_pw')
        _input['dirmgr_pass'] = conf.get('ldap', 'bind_pw')
        try:
            pw = pwd.getpwnam("dirsrv")
        except:
            _input['userid'] = "nobody"
            _input['group'] = "nobody"
        else:
            _input['userid'] = "dirsrv"
            _input['group'] = "dirsrv"

    # TODO: Verify the user and group exist.

    # TODO: This takes the system fqdn, domainname and hostname, rather then
    # the desired fqdn, domainname and hostname.
    #
    # 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'])

    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.
                    """))

        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.
                                """))

        _input['nodotdomain'] = _input['domain'].replace('.', '_')
        _input['rootdn'] = utils.standard_root_dn(_input['domain'])

        print >> sys.stderr, utils.multiline_message(
            _("""
                        The standard root dn we composed for you follows. Please
                        confirm this is the root dn you wish to use.
                    """))

        answer = utils.ask_confirmation("%s" % (_input['rootdn']))

        if not answer:
            positive_answer = False
            while not positive_answer:
                _input['rootdn'] = utils.ask_question(_("Root DN to use"))
                if not _input['rootdn'] == None and not _input['rootdn'] == "":
                    positive_answer = True
                else:
                    print >> sys.stderr, utils.multiline_message(
                        _("""
                                    Invalid input. Please try again.
                                """))

    # TODO: Loudly complain if the fqdn does not resolve back to this system.

    data = """
[General]
FullMachineName = %(fqdn)s
SuiteSpotUserID = %(userid)s
SuiteSpotGroup = %(group)s
AdminDomain = %(domain)s
ConfigDirectoryLdapURL = ldap://%(fqdn)s:389/o=NetscapeRoot
ConfigDirectoryAdminID = admin
ConfigDirectoryAdminPwd = %(admin_pass)s

[slapd]
SlapdConfigForMC = Yes
UseExistingMC = 0
ServerPort = 389
ServerIdentifier = %(hostname)s
Suffix = %(rootdn)s
RootDN = cn=Directory Manager
RootDNPwd = %(dirmgr_pass)s
ds_bename = %(nodotdomain)s
AddSampleEntries = No

[admin]
Port = 9830
ServerAdminID = admin
ServerAdminPwd = %(admin_pass)s
""" % (_input)

    (fp, filename) = tempfile.mkstemp(dir="/tmp/")
    os.write(fp, data)
    os.close(fp)

    if os.path.isfile("/usr/sbin/setup-ds-admin.pl"):
        setup_ds_admin = "/usr/sbin/setup-ds-admin.pl"
    #elif os.path.isfile("/usr/sbin/setup-ds-admin"):
    #setup_ds_admin = "/usr/sbin/setup-ds-admin"
    elif os.path.isfile("/usr/sbin/setup-ds.pl"):
        setup_ds_admin = "/usr/sbin/setup-ds.pl"
    elif os.path.isfile("/usr/sbin/setup-ds"):
        setup_ds_admin = "/usr/sbin/setup-ds"
    else:
        log.error(_("No directory server setup tool available."))
        sys.exit(1)

    command = [
        setup_ds_admin, '--debug', '--silent', '--force',
        '--file=%s' % (filename)
    ]

    print >> sys.stderr, utils.multiline_message(
        _("""
                    Setup is now going to set up the 389 Directory Server. This
                    may take a little while (during which period there is no
                    output and no progress indication).
                """))

    log.info(_("Setting up 389 Directory Server"))

    setup_389 = subprocess.Popen(command,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)

    (stdoutdata, stderrdata) = setup_389.communicate()

    if not setup_389.returncode == 0:
        print >> sys.stderr, utils.multiline_message(
            _("""
                        An error was detected in the setup procedure for 389
                        Directory Server. This setup will write out stderr and
                        stdout to /var/log/kolab/setup.error.log and
                        /var/log/kolab/setup.out.log respectively, before it
                        exits.
                    """))

        fp = open('/var/log/kolab/setup.error.log', 'w')
        fp.write(stderrdata)
        fp.close()

        fp = open('/var/log/kolab/setup.out.log', 'w')
        fp.write(stdoutdata)
        fp.close()

    log.debug(_("Setup DS stdout:"), level=8)
    log.debug(stdoutdata, level=8)

    log.debug(_("Setup DS stderr:"), level=8)
    log.debug(stderrdata, level=8)

    if not setup_389.returncode == 0:
        sys.exit(1)

    # Find the kolab schema. It's installed as %doc in the kolab-schema package.
    # TODO: Chown nobody, nobody, chmod 440
    schema_file = None
    for root, directories, filenames in os.walk('/usr/share/doc/'):
        for filename in filenames:
            if filename.startswith('kolab') and filename.endswith(
                    '.ldif') and schema_file == None:
                schema_file = os.path.join(root, filename)

    if not schema_file == None:
        try:
            shutil.copy(
                schema_file, '/etc/dirsrv/slapd-%s/schema/99%s' %
                (_input['hostname'], os.path.basename(schema_file)))

            schema_error = False
        except:
            log.error(_("Could not copy the LDAP extensions for Kolab"))
            schema_error = True
    else:
        log.error(_("Could not find the ldap Kolab schema file"))
        schema_error = True

    if os.path.isfile('/bin/systemctl'):
        subprocess.call(['/bin/systemctl', 'restart', 'dirsrv.target'])
        time.sleep(20)
    elif os.path.isfile('/sbin/service'):
        subprocess.call(['/sbin/service', 'dirsrv', 'restart'])
    elif os.path.isfile('/usr/sbin/service'):
        subprocess.call(['/usr/sbin/service', 'dirsrv', 'stop'])
        time.sleep(20)
        subprocess.call(['/usr/sbin/service', 'dirsrv', 'start'])
    else:
        log.error(_("Could not start the directory server service."))

    if os.path.isfile('/bin/systemctl'):
        subprocess.call(['/bin/systemctl', 'enable', 'dirsrv.target'])
    elif os.path.isfile('/sbin/chkconfig'):
        subprocess.call(['/sbin/chkconfig', 'dirsrv', 'on'])
    elif os.path.isfile('/usr/sbin/update-rc.d'):
        subprocess.call(['/usr/sbin/update-rc.d', 'dirsrv', 'defaults'])
    else:
        log.error(_("Could not configure to start on boot, the " + \
                "directory server service."))

    if ask_questions:
        print >> sys.stderr, utils.multiline_message(
            _("""
                        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')

    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', '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'])

    fp = open(conf.defaults.config_file, "w+")
    conf.cfg_parser.write(fp)
    fp.close()

    log.info(_("Inserting service users into LDAP."))

    # Insert service users
    auth = Auth(_input['domain'])
    auth.connect()
    auth._auth.connect()
    auth._auth._bind(bind_dn='cn=Directory Manager',
                     bind_pw=_input['dirmgr_pass'])

    dn = 'uid=%s,ou=Special Users,%s' % (conf.get(
        'cyrus-imap', 'admin_login'), _input['rootdn'])

    # A dict to help build the "body" of the object
    attrs = {}
    attrs['objectclass'] = [
        'top', 'person', 'inetorgperson', 'organizationalperson'
    ]
    attrs['uid'] = conf.get('cyrus-imap', 'admin_login')
    attrs['givenname'] = "Cyrus"
    attrs['surname'] = "Administrator"
    attrs['cn'] = "Cyrus Administrator"
    attrs['userPassword'] = _input['cyrus_admin_pass']

    # Convert our dict to nice syntax for the add-function using modlist-module
    ldif = ldap.modlist.addModlist(attrs)

    # Do the actual synchronous add-operation to the ldapserver
    auth._auth.ldap.add_s(dn, ldif)

    conf.command_set('cyrus-imap', 'admin_password',
                     _input['cyrus_admin_pass'])

    dn = 'uid=kolab-service,ou=Special Users,%s' % (_input['rootdn'])

    # A dict to help build the "body" of the object
    attrs = {}
    attrs['objectclass'] = [
        'top', 'person', 'inetorgperson', 'organizationalperson'
    ]
    attrs['uid'] = "kolab-service"
    attrs['givenname'] = "Kolab"
    attrs['surname'] = "Service"
    attrs['cn'] = "Kolab Service"
    attrs['userPassword'] = _input['kolab_service_pass']
    attrs['nslookthroughlimit'] = '-1'
    attrs['nssizelimit'] = '-1'
    attrs['nstimelimit'] = '-1'
    attrs['nsidletimeout'] = '-1'

    # Convert our dict to nice syntax for the add-function using modlist-module
    ldif = ldap.modlist.addModlist(attrs)

    # Do the actual synchronous add-operation to the ldapserver
    auth._auth.ldap.add_s(dn, ldif)

    dn = 'ou=Resources,%s' % (_input['rootdn'])

    # A dict to help build the "body" of the object
    attrs = {}
    attrs['objectclass'] = ['top', 'organizationalunit']
    attrs['ou'] = "Resources"

    # Convert our dict to nice syntax for the add-function using modlist-module
    ldif = ldap.modlist.addModlist(attrs)

    # Do the actual synchronous add-operation to the ldapserver
    auth._auth.ldap.add_s(dn, ldif)

    dn = 'ou=Shared Folders,%s' % (_input['rootdn'])

    # A dict to help build the "body" of the object
    attrs = {}
    attrs['objectclass'] = ['top', 'organizationalunit']
    attrs['ou'] = "Shared Folders"

    # Convert our dict to nice syntax for the add-function using modlist-module
    ldif = ldap.modlist.addModlist(attrs)

    # Do the actual synchronous add-operation to the ldapserver
    auth._auth.ldap.add_s(dn, ldif)

    log.info(_("Writing out cn=kolab,cn=config"))

    dn = 'cn=kolab,cn=config'

    # A dict to help build the "body" of the object
    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'])

    # Convert our dict to nice syntax for the add-function using modlist-module
    ldif = ldap.modlist.addModlist(attrs)

    # Do the actual synchronous add-operation to the ldapserver
    auth._auth.ldap.add_s(dn, ldif)

    log.info(
        _("Adding domain %s to list of domains for this deployment") %
        (_input['domain']))
    dn = "associateddomain=%s,cn=kolab,cn=config" % (_input['domain'])
    attrs = {}
    attrs['objectclass'] = ['top', 'domainrelatedobject']
    attrs['associateddomain'] = [
        '%s' % (_input['domain']),
        '%s' % (_input['fqdn']), 'localhost.localdomain', 'localhost'
    ]

    # De-duplicate attribute values before attempting to insert the object (#2205)
    attrs['associateddomain'] = list(set(attrs['associateddomain']))
    attrs['associateddomain'].pop(attrs['associateddomain'].index(
        _input['domain']))
    attrs['associateddomain'] = [_input['domain']] + attrs['associateddomain']

    attrs[
        'aci'] = '(targetattr = "*") (version 3.0;acl "Read Access for %(domain)s Users";allow (read,compare,search)(userdn = "ldap:///%(rootdn)s??sub?(objectclass=*)");)' % (
            _input)

    # Add inetdomainbasedn in case the configured root dn is not the same as the
    # standard root dn for the domain name configured
    if not _input['rootdn'] == utils.standard_root_dn(_input['domain']):
        attrs['objectclass'].append('inetdomain')
        attrs['inetdomainbasedn'] = _input['rootdn']

    ldif = ldap.modlist.addModlist(attrs)
    auth._auth.ldap.add_s(dn, ldif)

    if not conf.anonymous:
        log.info(_("Disabling anonymous binds"))
        dn = "cn=config"
        modlist = []
        modlist.append(
            (ldap.MOD_REPLACE, "nsslapd-allow-anonymous-access", "off"))
        auth._auth.ldap.modify_s(dn, modlist)

    # TODO: Ensure the uid attribute is unique
    # TODO^2: Consider renaming the general "attribute uniqueness to "uid attribute uniqueness"
    log.info(_("Enabling attribute uniqueness plugin"))
    dn = "cn=attribute uniqueness,cn=plugins,cn=config"
    modlist = []
    modlist.append((ldap.MOD_REPLACE, "nsslapd-pluginEnabled", "on"))
    auth._auth.ldap.modify_s(dn, modlist)

    log.info(_("Enabling referential integrity plugin"))
    dn = "cn=referential integrity postoperation,cn=plugins,cn=config"
    modlist = []
    modlist.append((ldap.MOD_REPLACE, "nsslapd-pluginEnabled", "on"))
    auth._auth.ldap.modify_s(dn, modlist)

    log.info(_("Enabling and configuring account policy plugin"))
    dn = "cn=Account Policy Plugin,cn=plugins,cn=config"
    modlist = []
    modlist.append((ldap.MOD_REPLACE, "nsslapd-pluginEnabled", "on"))
    modlist.append((ldap.MOD_ADD, "nsslapd-pluginarg0",
                    "cn=config,cn=Account Policy Plugin,cn=plugins,cn=config"))
    auth._auth.ldap.modify_s(dn, modlist)

    dn = "cn=config,cn=Account Policy Plugin,cn=plugins,cn=config"
    modlist = []
    modlist.append((ldap.MOD_REPLACE, "alwaysrecordlogin", "yes"))
    modlist.append((ldap.MOD_ADD, "stateattrname", "lastLoginTime"))
    modlist.append((ldap.MOD_ADD, "altstateattrname", "createTimestamp"))
    auth._auth.ldap.modify_s(dn, modlist)

    # Add kolab-admin role
    log.info(_("Adding the kolab-admin role"))
    dn = "cn=kolab-admin,%s" % (_input['rootdn'])
    attrs = {}
    attrs['description'] = "Kolab Administrator"
    attrs['objectClass'] = [
        'top', 'ldapsubentry', 'nsroledefinition', 'nssimpleroledefinition',
        'nsmanagedroledefinition'
    ]
    attrs['cn'] = "kolab-admin"
    ldif = ldap.modlist.addModlist(attrs)

    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']
    aci = []

    if schema_error:
        aci.append(
            '(targetattr = "carLicense || description || displayName || facsimileTelephoneNumber || homePhone || homePostalAddress || initials || jpegPhoto || l || labeledURI || mobile || o || pager || photo || postOfficeBox || postalAddress || postalCode || preferredDeliveryMethod || preferredLanguage || registeredAddress || roomNumber || secretary || seeAlso || st || street || telephoneNumber || telexNumber || title || userCertificate || userPassword || userSMIMECertificate || x500UniqueIdentifier") (version 3.0; acl "Enable self write for common attributes"; allow (read,compare,search,write)(userdn = "ldap:///self");)'
        )
    else:
        aci.append(
            '(targetattr = "carLicense || description || displayName || facsimileTelephoneNumber || homePhone || homePostalAddress || initials || jpegPhoto || l || labeledURI || mobile || o || pager || photo || postOfficeBox || postalAddress || postalCode || preferredDeliveryMethod || preferredLanguage || registeredAddress || roomNumber || secretary || seeAlso || st || street || telephoneNumber || telexNumber || title || userCertificate || userPassword || userSMIMECertificate || x500UniqueIdentifier || kolabDelegate || kolabInvitationPolicy || kolabAllowSMTPSender") (version 3.0; acl "Enable self write for common attributes"; allow (read,compare,search,write)(userdn = "ldap:///self");)'
        )

    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 "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))
    aci.append(
        '(targetattr != "userPassword") (version 3.0;acl "Search Access";allow (read,compare,search)(userdn = "ldap:///all");)'
    )
    modlist = []
    modlist.append((ldap.MOD_REPLACE, "aci", aci))
    auth._auth.ldap.modify_s(dn, modlist)

    if os.path.isfile('/bin/systemctl'):
        if not os.path.isfile('/usr/lib/systemd/system/dirsrv-admin.service'):
            log.info(_("directory server admin service not available"))
        else:
            subprocess.call(
                ['/bin/systemctl', 'enable', 'dirsrv-admin.service'])
    elif os.path.isfile('/sbin/chkconfig'):
        subprocess.call(['/sbin/chkconfig', 'dirsrv-admin', 'on'])
    elif os.path.isfile('/usr/sbin/update-rc.d'):
        subprocess.call(['/usr/sbin/update-rc.d', 'dirsrv-admin', 'defaults'])
    else:
        log.error(_("Could not start and configure to start on boot, the " + \
                "directory server admin service."))
Example #51
0
def handler(*args, **kw):
    auth = Auth()
    auth.connect()

    if len(args) == 4:
        # moddn, not relevant for Sieve Script Management
        pass

    elif len(args) == 3:
        dn = args[0]
        new = utils.normalize(args[1])
        old = utils.normalize(args[2])

        if isinstance(old, dict) and len(old.keys()) > 0:
            # Either the entry changed or was deleted

            if isinstance(new, dict) and len(new.keys()) > 0:
                # The entry was modified.

                result_attr = conf.get('cyrus-sasl', 'result_attribute')

                if result_attr not in new:
                    log.error("Entry %r does not have attribute %r" %
                              (dn, result_attr))

                    return

                # See if the mailserver_attribute exists
                mailserver_attribute = conf.get(
                    'ldap', 'mailserver_attribute').lower()

                if mailserver_attribute is None:
                    log.error("Mail server attribute is not set")
                    # TODO: Perhaps, query for IMAP servers. If there is only one,
                    #       we know what to do.
                    return

                if mailserver_attribute in new:
                    if not new[mailserver_attribute] == constants.fqdn:
                        log.info(
                            "The mail server for user %r is set, and it is not me (%r)"
                            % (dn, new[mailserver_attribute]))

                        return
                else:
                    log.error("Entry %r does not have a mail server set" %
                              (dn))
                    return

                conf.plugins.exec_hook('sieve_mgmt_refresh',
                                       kw={'user': new[result_attr]})

            else:
                # The entry was deleted. This is irrelevant for
                # Sieve Script Management
                return

        elif isinstance(new, dict) and len(new.keys()) > 0:
            # Old is not a dict (or empty), so the entry is just created

            # See if the mailserver_attribute exists
            mailserver_attribute = conf.get('ldap',
                                            'mailserver_attribute').lower()
            result_attr = conf.get('cyrus-sasl', 'result_attribute').lower()

            if mailserver_attribute is None:
                log.error("Mail server attribute is not set")
                # TODO: Perhaps, query for IMAP servers. If there is only one,
                #       we know what to do.
                return

            if mailserver_attribute in new:
                if not new[mailserver_attribute] == constants.fqdn:
                    log.info(
                        "The mail server for user %r is set, and it is not me (%r)"
                        % (dn, new[mailserver_attribute]))
                    return

                conf.plugins.exec_hook('sieve_mgmt_refresh',
                                       kw={'user': new[result_attr]})

        else:
            log.info("entry %r changed, but no new or old attributes" % (dn))
Example #52
0
    def do_saslauthd(self):
        """
            Create the actual listener socket, and handle the authentication.

            The actual authentication handling is passed on to the appropriate
            backend authentication classes through the more generic Auth().
        """
        import binascii
        import socket
        import struct

        s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)

        # TODO: The saslauthd socket path could be a setting.
        try:
            os.remove(conf.socketfile)
        except:
            # TODO: Do the "could not remove, could not start" dance
            pass

        s.bind(conf.socketfile)
        os.chmod(conf.socketfile, 0777)

        s.listen(5)

        while 1:
            max_tries = 20
            cur_tries = 0
            bound = False
            while not bound:
                cur_tries += 1
                try:
                    (clientsocket, address) = s.accept()
                    bound = True
                except Exception, errmsg:
                    log.error(
                        _("kolab-saslauthd could not accept " +
                          "connections on socket: %r") % (errmsg))

                    if cur_tries >= max_tries:
                        log.fatal(_("Maximum tries exceeded, exiting"))
                        sys.exit(1)

                    time.sleep(1)

            received = clientsocket.recv(4096)

            login = []

            start = 0
            end = 2

            while end < len(received):
                (length, ) = struct.unpack("!H", received[start:end])
                start += 2
                end += length
                (value, ) = struct.unpack("!%ds" % (length),
                                          received[start:end])
                start += length
                end = start + 2
                login.append(value)

            if len(login) == 4:
                realm = login[3]
            elif len(login[0].split('@')) > 1:
                realm = login[0].split('@')[1]
            else:
                realm = conf.get('kolab', 'primary_domain')

            auth = Auth(domain=realm)
            auth.connect()

            success = False

            try:
                success = auth.authenticate(login)
            except:
                success = False

            if success:
                # #1170: Catch broken pipe error (incomplete authentication request)
                try:
                    clientsocket.send(struct.pack("!H2s", 2, "OK"))
                except:
                    pass
            else:
                # #1170: Catch broken pipe error (incomplete authentication request)
                try:
                    clientsocket.send(struct.pack("!H2s", 2, "NO"))
                except:
                    pass

            clientsocket.close()
            auth.disconnect()
Example #53
0
def synchronize_once():
    auth = Auth()
    auth.connect()
    auth.synchronize(mode='_paged_search')
Example #54
0
def execute(*args, **kw):
    """
        Synchronize or display changes
    """

    imap = IMAP()

    if not conf.connect_server == None:
        imap.connect(server=conf.connect_server)
    else:
        imap.connect()

    auth = Auth()
    auth.connect()

    result_attribute = conf.get('cyrus-sasl', 'result_attribute')
    if result_attribute is None:
        result_attribute = 'mail'

    domains = auth.list_domains()
    folders = imap.lm()

    imap_domains_not_domains = []

    for folder in folders:
        if len(folder.split('@')) > 1 and not folder.startswith('DELETED'):
            _folder_domain = folder.split('@')[-1]
            if not _folder_domain in list(
                    set(domains.keys() + domains.values())):
                imap_domains_not_domains.append(folder.split('@')[-1])

    imap_domains_not_domains = list(set(imap_domains_not_domains))

    log.debug(_("Domains in IMAP not in LDAP: %r") %
              (imap_domains_not_domains),
              level=8)

    if len(imap_domains_not_domains) > 0:
        for domain in imap_domains_not_domains:
            folders = []

            folders.extend(imap.lm('shared/%%@%s' % (domain)))
            folders.extend(imap.lm('user/%%@%s' % (domain)))

            for folder in folders:
                r_folder = folder
                if not folder.startswith('shared/'):
                    r_folder = '/'.join(folder.split('/')[1:])

                if conf.delete:
                    if conf.dry_run:
                        if not folder.startswith('shared/'):
                            log.warning(
                                _("No recipients for '%s' (would have deleted the mailbox if not for --dry-run)!"
                                  ) % (r_folder))
                        else:
                            continue
                    else:
                        if not folder.startswith('shared/'):
                            log.info(
                                _("Deleting mailbox '%s' because it has no recipients"
                                  ) % (folder))
                            try:
                                imap.dm(folder)
                            except Exception, errmsg:
                                log.error(
                                    _("An error occurred removing mailbox %r: %r"
                                      ) % (folder, errmsg))
                        else:
                            log.info(
                                _("Not automatically deleting shared folder '%s'"
                                  ) % (folder))
                else:
                    log.warning(
                        _("No recipients for '%s' (use --delete to delete)!") %
                        (r_folder))
Example #55
0
    return """Remove a recipient's mail address."""

def execute(*args, **kw):
    try:
        email_address = conf.cli_args.pop(0)
    except IndexError, errmsg:
        email_address = utils.ask_question("Email address to remove")

    # Get the domain from the email address
    if len(email_address.split('@')) > 1:
        domain = email_address.split('@')[1]
    else:
        log.error(_("Invalid or unqualified email address."))
        sys.exit(1)

    auth = Auth()
    auth.connect(domain=domain)
    recipients = auth.find_recipient(email_address)

    if len(recipients) == 0:
        log.error(_("No recipient found for email address %r") % (email_address))
        sys.exit(1)

    log.debug(_("Found the following recipient(s): %r") % (recipients), level=8)

    mail_attributes = conf.get_list(domain, 'mail_attributes')
    if mail_attributes == None or len(mail_attributes) < 1:
        mail_attributes = conf.get_list(conf.get('kolab', 'auth_mechanism'), 'mail_attributes')

    log.debug(_("Using the following mail attributes: %r") % (mail_attributes), level=8)
Example #56
0
def execute(*args, **kw):
    try:
        address = conf.cli_args.pop(0)
    except:
        address = utils.ask_question(_("Email Address"))

    auth = Auth()
    auth.connect()

    user = auth.find_recipient(address)

    # Get the main, default backend
    backend = conf.get('kolab', 'imap_backend')

    if len(address.split('@')) > 1:
        domain = address.split('@')[1]
    else:
        domain = conf.get('kolab', 'primary_domain')

    if conf.has_section(domain) and conf.has_option(domain, 'imap_backend'):
        backend = conf.get(domain, 'imap_backend')

    if conf.has_section(domain) and conf.has_option(domain, 'imap_uri'):
        uri = conf.get(domain, 'imap_uri')
    else:
        uri = conf.get(backend, 'uri')

    hostname = None
    port = None

    result = urlparse(uri)

    if hasattr(result, 'hostname'):
        hostname = result.hostname
    else:
        scheme = uri.split(':')[0]
        (hostname, port) = uri.split('/')[2].split(':')

    port = 4190

    # Get the credentials
    admin_login = conf.get(backend, 'admin_login')
    admin_password = conf.get(backend, 'admin_password')

    import sievelib.managesieve

    sieveclient = sievelib.managesieve.Client(hostname, port,
                                              conf.debuglevel > 8)

    sieveclient.connect(None, None, True)

    result = sieveclient._plain_authentication(admin_login, admin_password,
                                               address)

    if not result:
        print "LOGIN FAILED??"

    sieveclient.authenticated = True

    result = sieveclient.listscripts()

    if result == None:
        print "No scripts"
        sys.exit(0)

    (active, scripts) = result

    print "%s (active)" % (active)
    for script in scripts:
        print script
Example #57
0
def execute(*args, **kw):
    try:
        address = conf.cli_args.pop(0)
    except:
        address = utils.ask_question(_("Email Address"))

    auth = Auth()
    auth.connect()

    user = auth.find_recipient(address)

    # Get the main, default backend
    backend = conf.get('kolab', 'imap_backend')

    if len(address.split('@')) > 1:
        domain = address.split('@')[1]
    else:
        domain = conf.get('kolab', 'primary_domain')

    if conf.has_section(domain) and conf.has_option(domain, 'imap_backend'):
        backend = conf.get(domain, 'imap_backend')

    if conf.has_section(domain) and conf.has_option(domain, 'imap_uri'):
        uri = conf.get(domain, 'imap_uri')
    else:
        uri = conf.get(backend, 'uri')

    hostname = None
    port = None

    result = urlparse(uri)

    if hasattr(result, 'hostname'):
        hostname = result.hostname
    else:
        scheme = uri.split(':')[0]
        (hostname, port) = uri.split('/')[2].split(':')

    port = 4190

    # Get the credentials
    admin_login = conf.get(backend, 'admin_login')
    admin_password = conf.get(backend, 'admin_password')

    import sievelib.managesieve

    sieveclient = sievelib.managesieve.Client(hostname, port,
                                              conf.debuglevel > 8)
    sieveclient.connect(None, None, True)
    sieveclient._plain_authentication(admin_login, admin_password, address)
    sieveclient.authenticated = True

    result = sieveclient.listscripts()

    if result == None:
        active = None
        scripts = []
    else:
        active, scripts = result

    log.debug(_("Found the following scripts for user %s: %s") %
              (address, ','.join(scripts)),
              level=8)
    log.debug(_("And the following script is active for user %s: %s") %
              (address, active),
              level=8)

    mgmt_required_extensions = []

    mgmt_script = """#
# MANAGEMENT
#
"""

    user = auth.get_entry_attributes(domain, user, ['*'])

    #
    # Vacation settings (a.k.a. Out of Office)
    #
    vacation_active = None
    vacation_text = None
    vacation_uce = None
    vacation_noreact_domains = None
    vacation_react_domains = None

    vacation_active_attr = conf.get('sieve', 'vacation_active_attr')
    vacation_text_attr = conf.get('sieve', 'vacation_text_attr')
    vacation_uce_attr = conf.get('sieve', 'vacation_uce_attr')
    vacation_noreact_domains_attr = conf.get('sieve',
                                             'vacation_noreact_domains_attr')
    vacation_react_domains_attr = conf.get('sieve',
                                           'vacation_react_domains_attr')

    if not vacation_text_attr == None:

        if user.has_key(vacation_active_attr):
            vacation_active = utils.true_or_false(user[vacation_active_attr])
        else:
            vacation_active = False

        if user.has_key(vacation_text_attr):
            vacation_text = user[vacation_text_attr]
        else:
            vacation_active = False

        if user.has_key(vacation_uce_attr):
            vacation_uce = utils.true_or_false(user[vacation_uce_attr])
        else:
            vacation_uce = False

        if user.has_key(vacation_react_domains_attr):
            if isinstance(user[vacation_react_domains_attr], list):
                vacation_react_domains = user[vacation_react_domains_attr]
            else:
                vacation_react_domains = [user[vacation_react_domains_attr]]
        else:
            if user.has_key(vacation_noreact_domains_attr):
                if isinstance(user[vacation_noreact_domains_attr], list):
                    vacation_noreact_domains = user[
                        vacation_noreact_domains_attr]
                else:
                    vacation_noreact_domains = [
                        user[vacation_noreact_domains_attr]
                    ]
            else:
                vacation_noreact_domains = []

    #
    # Delivery to Folder
    #
    dtf_active_attr = conf.get('sieve', 'deliver_to_folder_active')
    if not dtf_active_attr == None:
        if user.has_key(dtf_active_attr):
            dtf_active = utils.true_or_false(user[dtf_active_attr])
        else:
            dtf_active = False
    else:
        # TODO: Not necessarily de-activated, the *Active attributes are
        # not supposed to charge this - check the deliver_to_folder_attr
        # attribute value for a value.
        dtf_active = False

    if dtf_active:
        dtf_folder_name_attr = conf.get('sieve', 'deliver_to_folder_attr')
        if not dtf_folder_name_attr == None:
            if user.has_key(dtf_folder_name_attr):
                dtf_folder = user[dtf_folder_name_attr]
            else:
                log.warning(
                    _("Delivery to folder active, but no folder name attribute available for user %r"
                      ) % (user))
                dtf_active = False
        else:
            log.error(
                _("Delivery to folder active, but no folder name attribute configured"
                  ))
            dtf_active = False

    #
    # Folder name to delivery spam to.
    #
    # Global or local.
    #
    sdf_filter = True
    sdf = conf.get('sieve', 'spam_global_folder')

    if sdf == None:
        sdf = conf.get('sieve', 'spam_personal_folder')
        if sdf == None:
            sdf_filter = False

    #
    # Mail forwarding
    #
    forward_active = None
    forward_addresses = []
    forward_keepcopy = None
    forward_uce = None

    forward_active_attr = conf.get('sieve', 'forward_address_active')
    if not forward_active_attr == None:
        if user.has_key(forward_active_attr):
            forward_active = utils.true_or_false(user[forward_active_attr])
        else:
            forward_active = False

    if not forward_active == False:
        forward_address_attr = conf.get('sieve', 'forward_address_attr')
        if user.has_key(forward_address_attr):
            if isinstance(user[forward_address_attr], basestring):
                forward_addresses = [user[forward_address_attr]]
            elif isinstance(user[forward_address_attr], str):
                forward_addresses = [user[forward_address_attr]]
            else:
                forward_addresses = user[forward_address_attr]

        if len(forward_addresses) == 0:
            forward_active = False

        forward_keepcopy_attr = conf.get('sieve', 'forward_keepcopy_active')
        if not forward_keepcopy_attr == None:
            if user.has_key(forward_keepcopy_attr):
                forward_keepcopy = utils.true_or_false(
                    user[forward_keepcopy_attr])
            else:
                forward_keepcopy = False

        forward_uce_attr = conf.get('sieve', 'forward_uce_active')
        if not forward_uce_attr == None:
            if user.has_key(forward_uce_attr):
                forward_uce = utils.true_or_false(user[forward_uce_attr])
            else:
                forward_uce = False

    if vacation_active:
        mgmt_required_extensions.append('vacation')
        mgmt_required_extensions.append('envelope')

    if dtf_active:
        mgmt_required_extensions.append('fileinto')

    if forward_active and (len(forward_addresses) > 1 or forward_keepcopy):
        mgmt_required_extensions.append('copy')

    if sdf_filter:
        mgmt_required_extensions.append('fileinto')

    import sievelib.factory

    mgmt_script = sievelib.factory.FiltersSet("MANAGEMENT")

    for required_extension in mgmt_required_extensions:
        mgmt_script.require(required_extension)

    mgmt_script.require('fileinto')

    if vacation_active:
        if not vacation_react_domains == None and len(
                vacation_react_domains) > 0:
            mgmt_script.addfilter(
                'vacation',
                [('envelope', ':domain', ":is", "from", vacation_react_domains)
                 ],
                [(
                    "vacation",
                    ":days",
                    1,
                    ":subject",
                    "Out of Office",
                    # ":handle", see http://tools.ietf.org/html/rfc5230#page-4
                    # ":mime", to indicate the reason is in fact MIME
                    vacation_text)])

        elif not vacation_noreact_domains == None and len(
                vacation_noreact_domains) > 0:
            mgmt_script.addfilter(
                'vacation',
                [('not', ('envelope', ':domain', ":is", "from",
                          vacation_noreact_domains))],
                [(
                    "vacation",
                    ":days",
                    1,
                    ":subject",
                    "Out of Office",
                    # ":handle", see http://tools.ietf.org/html/rfc5230#page-4
                    # ":mime", to indicate the reason is in fact MIME
                    vacation_text)])

        else:
            mgmt_script.addfilter(
                'vacation',
                [('true', )],
                [(
                    "vacation",
                    ":days",
                    1,
                    ":subject",
                    "Out of Office",
                    # ":handle", see http://tools.ietf.org/html/rfc5230#page-4
                    # ":mime", to indicate the reason is in fact MIME
                    vacation_text)])

    if forward_active:
        forward_rules = []

        # Principle can be demonstrated by:
        #
        # python -c "print ','.join(['a','b','c'][:-1])"
        #
        for forward_copy in forward_addresses[:-1]:
            forward_rules.append(("redirect", ":copy", forward_copy))

        if forward_keepcopy:
            # Principle can be demonstrated by:
            #
            # python -c "print ','.join(['a','b','c'][-1])"
            #
            if forward_uce:
                rule_name = 'forward-uce-keepcopy'
            else:
                rule_name = 'forward-keepcopy'

            forward_rules.append(("redirect", ":copy", forward_addresses[-1]))
        else:
            if forward_uce:
                rule_name = 'forward-uce'
            else:
                rule_name = 'forward'

            forward_rules.append(("redirect", forward_addresses[-1]))
            forward_rules.append(("stop"))

        if forward_uce:
            mgmt_script.addfilter(rule_name, ['true'], forward_rules)

        else:
            # NOTE: Messages with no X-Spam-Status header need to be matched
            # too, and this does exactly that.
            mgmt_script.addfilter(rule_name,
                                  [("not",
                                    ("X-Spam-Status", ":matches", "Yes,*"))],
                                  forward_rules)

    if sdf_filter:
        mgmt_script.addfilter('spam_delivery_folder',
                              [("X-Spam-Status", ":matches", "Yes,*")],
                              [("fileinto", "INBOX/Spam"), ("stop")])

    if dtf_active:
        mgmt_script.addfilter('delivery_to_folder', ['true'],
                              [("fileinto", dtf_folder)])

    mgmt_script = mgmt_script.__str__()

    log.debug(_("MANAGEMENT script for user %s contents: %r") %
              (address, mgmt_script),
              level=9)

    result = sieveclient.putscript("MANAGEMENT", mgmt_script)

    if not result:
        log.error(
            _("Uploading script MANAGEMENT failed for user %s") % (address))
    else:
        log.debug(_("Uploading script MANAGEMENT for user %s succeeded") %
                  (address),
                  level=8)

    user_script = """#
# User
#

require ["include"];
"""

    for script in scripts:
        if not script in ["MASTER", "MANAGEMENT", "USER"]:
            log.debug(_("Including script %s in USER (for user %s)") %
                      (script, address),
                      level=8)
            user_script = """%s

include :personal "%s";
""" % (user_script, script)

    result = sieveclient.putscript("USER", user_script)

    if not result:
        log.error(_("Uploading script USER failed for user %s") % (address))
    else:
        log.debug(_("Uploading script USER for user %s succeeded") % (address),
                  level=8)

    result = sieveclient.putscript(
        "MASTER", """#
# MASTER
#
# This file is authoritative for your system and MUST BE KEPT ACTIVE.
#
# Altering it is likely to render your account dysfunctional and may
# be violating your organizational or corporate policies.
#
# For more information on the mechanism and the conventions behind
# this script, see http://wiki.kolab.org/KEP:14
#

require ["include"];

# OPTIONAL: Includes for all or a group of users
# include :global "all-users";
# include :global "this-group-of-users";

# The script maintained by the general management system
include :personal "MANAGEMENT";

# The script(s) maintained by one or more editors available to the user
include :personal "USER";
""")

    if not result:
        log.error(_("Uploading script MASTER failed for user %s") % (address))
    else:
        log.debug(_("Uploading script MASTER for user %s succeeded") %
                  (address),
                  level=8)

    sieveclient.setactive("MASTER")
Example #58
0
                        _("No recipients for '%s' (use --delete to delete)!") %
                        (r_folder))

    for primary in list(set(domains.values())):
        secondaries = [x for x in domains.keys() if domains[x] == primary]

        folders = []

        folders.extend(imap.lm('shared/%%@%s' % (primary)))
        folders.extend(imap.lm('user/%%@%s' % (primary)))

        for secondary in secondaries:
            folders.extend(imap.lm('shared/%%@%s' % (secondary)))
            folders.extend(imap.lm('user/%%@%s' % (secondary)))

        auth = Auth(domain=primary)
        auth.connect()

        for folder in folders:
            server = imap.user_mailbox_server(folder)
            r_folder = folder

            if folder.startswith('shared/'):
                recipient = auth.find_folder_resource(folder)
            else:
                r_folder = '/'.join(folder.split('/')[1:])
                recipient = auth.find_recipient(
                    r_folder, search_attrs=[result_attribute])

            if (isinstance(recipient, list)):
                if len(recipient) > 1:
Example #59
0
def execute(*args, **kw):
    """
        List mailboxes
    """

    auth = Auth()
    domains = auth.list_domains()

    imap = IMAP()
    imap.connect()

    domain_folders = {}

    subjects = []
    # Placeholder for subjects that would have already been deleted
    subjects_deleted = []

    for domain in domains.keys():
        domain_folders[domain] = imap.lm("user/%%@%s" % (domain))

    for domain in domain_folders.keys():
        auth = Auth(domain=domain)
        auth.connect(domain)

        for folder in domain_folders[domain]:
            user = folder.replace('user/', '')

            try:
                recipient = auth.find_recipient(user)
            except ldap.NO_SUCH_OBJECT, errmsg:
                if not user in subjects_deleted and conf.dryrun:
                    subjects_deleted.append(user)

                if conf.dryrun:
                    log.info(
                        _("Would have deleted folder 'user/%s' (dryrun)") %
                        (user))
                else:
                    log.info(_("Deleting folder 'user/%s'") % (user))
                continue

            if len(recipient) == 0 or recipient == []:
                if not user in subjects_deleted and conf.dryrun:
                    subjects_deleted.append(user)

                if conf.dryrun:
                    log.info(
                        _("Would have deleted folder 'user/%s' (dryrun)") %
                        (user))
                else:
                    log.info(_("Deleting folder 'user/%s'") % (user))
                    try:
                        imap.dm(folder)
                    except:
                        log.error(
                            _("Error deleting folder 'user/%s'") % (user))
            else:
                log.debug(_("Valid recipient found for 'user/%s'") % (user),
                          level=6)

                if not user in subjects:
                    subjects.append(user)
Example #60
0
    def do_sync(self):
        domain_auth = {}

        pid = os.getpid()

        primary_domain = conf.get('kolab', 'primary_domain')

        while 1:
            primary_auth = Auth(primary_domain)

            connected = False
            while not connected:
                try:
                    primary_auth.connect()
                    connected = True
                except Exception, errmsg:
                    connected = False
                    log.error(_("Could not connect to LDAP, is it running?"))
                    time.sleep(5)

            log.debug(_("Listing domains..."), level=5)

            start = time.time()

            try:
                domains = primary_auth.list_domains()
            except:
                time.sleep(60)
                continue

            if isinstance(domains, list) and len(domains) < 1:
                log.error(_("No domains. Not syncing"))
                time.sleep(5)
                continue

            # domains now is a list of key-valye pairs in the format of
            # {'secondary': 'primary'}, we want the primaries
            primaries = list(set(domains.values()))

            # Store the naming contexts for the domains as
            #
            #   {'domain': 'naming context'}
            #
            # and the domain root dns as
            #
            #   {'domain': 'domain root dn'}
            #
            domain_root_dns = {}
            naming_contexts = {}

            for primary in primaries:
                naming_context = primary_auth.domain_naming_context(primary)
                domain_root_dn = primary_auth._auth._kolab_domain_root_dn(
                    primary)
                log.debug(_("Domain %r naming context: %r, root dn: %r") %
                          (primary, naming_context, domain_root_dn),
                          level=8)

                domain_root_dns[primary] = domain_root_dn
                naming_contexts[primary] = naming_context

            log.debug(_("Naming contexts to synchronize: %r") %
                      (list(set(naming_contexts.values()))),
                      level=8)

            # Find however many naming contexts we have, and what the
            # corresponding domain name is for them.
            primary_domains = [
                x for x, y in naming_contexts.iteritems()
                if domain_root_dns[x] == y
            ]

            # Now we can check if any changes happened.
            added_domains = []
            removed_domains = []

            # Combine the domains from LDAP with the domain processes
            # accounted for locally.
            all_domains = list(set(primary_domains + domain_auth.keys()))

            log.debug(_("Result set of domains: %r") % (all_domains), level=8)

            for domain in all_domains:
                log.debug(_("Checking for domain %s") % (domain), level=8)

                if domain in domain_auth.keys() and domain in primary_domains:
                    if not domain_auth[domain].is_alive():
                        log.debug(_("Domain %s isn't alive anymore.") %
                                  (domain),
                                  level=8)
                        domain_auth[domain].terminate()
                        added_domains.append(domain)
                    else:
                        log.debug(_("Domain %s already there and alive.") %
                                  (domain),
                                  level=8)
                        continue

                elif domain in domain_auth.keys():
                    log.debug(_("Domain %s should not exist any longer.") %
                              (domain),
                              level=8)
                    removed_domains.append(domain)
                else:
                    log.debug(_("Domain %s does not have a process yet.") %
                              (domain),
                              level=8)
                    added_domains.append(domain)

            if len(removed_domains) == 0 and len(added_domains) == 0:
                try:
                    sleep_between_domain_operations_in_seconds = (float)(
                        conf.get('kolab', 'domain_sync_interval'))
                    time.sleep(sleep_between_domain_operations_in_seconds)
                except ValueError:
                    time.sleep(600)

            log.debug(_("added domains: %r, removed domains: %r") %
                      (added_domains, removed_domains),
                      level=8)

            for domain in added_domains:
                domain_auth[domain] = Process(domain)
                domain_auth[domain].start()

                # Pause or hammer your LDAP server to death
                if len(added_domains) >= 5:
                    time.sleep(10)

            for domain in removed_domains:
                domain_auth[domain].terminate()
                del domain_auth[domain]