Beispiel #1
0
def is_email_exists(mail, conn=None):
    mail = str(mail).lower()
    mail = utils.strip_mail_ext_address(mail)

    if not utils.is_email(mail):
        return True

    # Filter used to search mail accounts.
    query_filter = '(&'
    query_filter += '(|(objectClass=mailUser)(objectClass=mailList)(objectClass=mailingList)(objectClass=mailAlias))'
    query_filter += '(|(mail=%s)(shadowAddress=%s))' % (mail, mail)
    query_filter += ')'

    try:
        if not conn:
            _wrap = LDAPWrap()
            conn = _wrap.conn

        qr = conn.search_s(settings.iredmail_ldap_basedn,
                           ldap.SCOPE_SUBTREE,
                           query_filter,
                           ['dn'])

        if qr:
            return True
        else:
            # Account not exist.
            return False
    except:
        # Account 'EXISTS' (fake) if lookup failed.
        return True
Beispiel #2
0
def _block_sender(sender):
    if not settings.SPAM_TRAP_BLOCK_SENDER:
        return (True, )

    conn = utils.get_db_conn('amavisd')
    _s = utils.strip_mail_ext_address(mail=sender)
    qr = wblist.add_wblist(
        conn=conn,
        account='@.',  # server-wide block
        bl_senders=[_s],
        flush_before_import=False)

    return qr
Beispiel #3
0
    def found_terminator(self):
        if self.buffer:
            # Format received data
            line = self.buffer.pop().decode()

            if '=' in line:
                logger.debug("[policy] {}".format(line))
                (k, v) = line.split('=', 1)

                if k in SMTP_SESSION_ATTRIBUTES:
                    # Convert to lower cases.
                    if k in ['sender', 'recipient', 'sasl_username', 'reverse_client_name']:
                        v = v.lower()
                        self.smtp_session_data[k] = v

                    # Verify email address format
                    if k in ['sender', 'recipient', 'sasl_username']:
                        if v:
                            if not utils.is_email(v):
                                # Don't waste time on invalid email addresses.
                                action = SMTP_ACTIONS['default'] + ' Error: Invalid {} address: {}'.format(k, v)
                                self.push('action=' + action + '\n')

                        self.smtp_session_data[k] = v

                        # Add sender_domain, recipient_domain, sasl_username_domain
                        self.smtp_session_data[k + '_domain'] = v.split('@', 1)[-1]

                        if k in ['sender', 'recipient']:
                            # Add sender_without_ext, recipient_without_ext
                            self.smtp_session_data[k + '_without_ext'] = utils.strip_mail_ext_address(v)
                    else:
                        self.smtp_session_data[k] = v
                else:
                    logger.debug("[policy] Drop invalid smtp session input: {}".format(line))

        elif self.smtp_session_data:
            # Track how long a request takes
            _start_time = time.time()

            # Gather data at RCPT , data will be used at END-OF-MESSAGE
            _protocol_state = self.smtp_session_data['protocol_state']

            # Call modeler and apply plugins
            try:
                modeler = Modeler(conns=self.db_conns)
                result = modeler.handle_data(
                    smtp_session_data=self.smtp_session_data,
                    plugins=self.plugins,
                    sender_search_attrlist=self.sender_search_attrlist,
                    recipient_search_attrlist=self.recipient_search_attrlist,
                )

                if result:
                    action = result
                else:
                    action = SMTP_ACTIONS['default']
                    logger.error("No result returned by modeler, fallback to default action: {}.".format(action))

            except Exception as e:
                action = SMTP_ACTIONS['default']
                logger.error("Unexpected error: {}. Fallback to default action: {}".format(repr(e), action))

            self.push('action=' + action + '\n')
            logger.debug("Session ended.")

            _end_time = time.time()
            utils.log_policy_request(smtp_session_data=self.smtp_session_data,
                                     action=action,
                                     start_time=_start_time,
                                     end_time=_end_time)

            # Log smtp session.
            # Postfix may send the smtp session data twice or even more if
            # iRedAPD is called in multiple protocol states, try to avoid
            # "duplicate" logging here.
            if _protocol_state == 'END-OF-MESSAGE' or \
               (_protocol_state == 'RCPT' and not action.startswith('DUNNO')):
                utils.log_smtp_session(conn=self.db_conns['conn_iredapd'],
                                       smtp_action=action,
                                       **self.smtp_session_data)
        else:
            action = SMTP_ACTIONS['default']
            logger.debug("replying: {}".format(action))
            self.push('action=' + action + '\n')
            logger.debug("Session ended")
Beispiel #4
0
    def found_terminator(self):
        if self.buffer:
            # Format received data
            line = self.buffer.pop().decode()

            if '=' in line:
                logger.debug("[policy] " + line)
                (k, v) = line.split('=', 1)

                if k in SMTP_SESSION_ATTRIBUTES:
                    # Convert to lower cases.
                    if k in ['sender', 'recipient', 'sasl_username', 'reverse_client_name']:
                        v = v.lower()
                        self.smtp_session_data[k] = v

                    # Verify email address format
                    if k in ['sender', 'recipient', 'sasl_username']:
                        if v:
                            if not utils.is_email(v):
                                # Don't waste time on invalid email addresses.
                                action = SMTP_ACTIONS['default'] + ' Error: Invalid %s address: %s' % (k, v)
                                self.push('action=' + action + '\n')

                        self.smtp_session_data[k] = v

                        # Add sender_domain, recipient_domain, sasl_username_domain
                        self.smtp_session_data[k + '_domain'] = v.split('@', 1)[-1]

                        if k in ['sender', 'recipient']:
                            # Add sender_without_ext, recipient_without_ext
                            self.smtp_session_data[k + '_without_ext'] = utils.strip_mail_ext_address(v)
                    else:
                        self.smtp_session_data[k] = v
                else:
                    logger.debug(f"[policy] Drop invalid smtp session input: {line}")

        elif self.smtp_session_data:
            # Track how long a request takes
            _start_time = time.time()

            # Gather data at RCPT , data will be used at END-OF-MESSAGE
            _instance = self.smtp_session_data['instance']
            _protocol_state = self.smtp_session_data['protocol_state']

            if _protocol_state == 'RCPT':
                if _instance not in settings.GLOBAL_SESSION_TRACKING:
                    # add timestamp of tracked smtp instance, so that we can
                    # remove them after instance finished.
                    _tracking_expired = int(time.time())

                    # @num_processed: count of processed smtp sessions
                    settings.GLOBAL_SESSION_TRACKING[_instance] = {
                        'num_processed': 0,
                        'expired': _tracking_expired,
                    }
                else:
                    settings.GLOBAL_SESSION_TRACKING[_instance]['num_processed'] += 1

            # Call modeler and apply plugins
            try:
                modeler = Modeler(conns=self.db_conns)
                result = modeler.handle_data(
                    smtp_session_data=self.smtp_session_data,
                    plugins=self.plugins,
                    sender_search_attrlist=self.sender_search_attrlist,
                    recipient_search_attrlist=self.recipient_search_attrlist,
                )

                if result:
                    action = result
                else:
                    action = SMTP_ACTIONS['default']
                    logger.error(f'No result returned by modeler, fallback to default action: {action}.')

            except Exception as e:
                action = SMTP_ACTIONS['default']
                logger.error(f"Unexpected error: {e}. Fallback to default action: {action}")

            # Remove tracking data when:
            #
            #   - session was rejected/discard/whitelisted ('OK') during
            #     RCPT state (it never reach END-OF-MESSAGE state)
            #   - session is in last state (END-OF-MESSAGE)
            if (not action.startswith('DUNNO')) or (_protocol_state == 'END-OF-MESSAGE'):
                if _instance in settings.GLOBAL_SESSION_TRACKING:
                    settings.GLOBAL_SESSION_TRACKING.pop(_instance)
                else:
                    # Remove expired/ghost data.
                    for i in settings.GLOBAL_SESSION_TRACKING:
                        if settings.GLOBAL_SESSION_TRACKING[i]['expired'] + 60 < int(time.time()):
                            settings.GLOBAL_SESSION_TRACKING.pop(_instance)

            self.push('action=' + action + '\n')
            logger.debug('Session ended.')

            _end_time = time.time()
            utils.log_policy_request(smtp_session_data=self.smtp_session_data,
                                     action=action,
                                     start_time=_start_time,
                                     end_time=_end_time)

            # Log smtp session.
            # Postfix may send the smtp session data twice or even more if
            # iRedAPD is called in multiple protocol states, try to avoid
            # "duplicate" logging here.
            if _protocol_state == 'END-OF-MESSAGE' or \
               (_protocol_state == 'RCPT' and not action.startswith('DUNNO')):
                utils.log_smtp_session(conn=self.db_conns['conn_iredapd'],
                                       smtp_action=action,
                                       **self.smtp_session_data)
        else:
            action = SMTP_ACTIONS['default']
            logger.debug("replying: " + action)
            self.push('action=' + action + '\n')
            logger.debug("Session ended")
Beispiel #5
0
    def found_terminator(self):
        if self.buffer:
            # Format received data
            line = self.buffer.pop().decode()

            if '=' in line:
                logger.debug("[policy] {}".format(line))
                (k, v) = line.split('=', 1)

                if k in SMTP_SESSION_ATTRIBUTES:
                    # Convert to lower cases.
                    if k in [
                            'sender', 'recipient', 'sasl_username',
                            'reverse_client_name'
                    ]:
                        v = v.lower()
                        self.smtp_session_data[k] = v

                    # Verify email address format
                    if k in ['sender', 'recipient', 'sasl_username']:
                        if v:
                            if not utils.is_email(v):
                                # Don't waste time on invalid email addresses.
                                action = SMTP_ACTIONS[
                                    'default'] + ' Error: Invalid {} address: {}'.format(
                                        k, v)
                                self.push('action=' + action + '\n')

                        self.smtp_session_data[k] = v

                        # Add sender_domain, recipient_domain, sasl_username_domain
                        self.smtp_session_data[k + '_domain'] = v.split(
                            '@', 1)[-1]

                        if k in ['sender', 'recipient']:
                            # Add sender_without_ext, recipient_without_ext
                            self.smtp_session_data[
                                k +
                                '_without_ext'] = utils.strip_mail_ext_address(
                                    v)
                    else:
                        self.smtp_session_data[k] = v
                else:
                    logger.debug(
                        "[policy] Drop invalid smtp session input: {}".format(
                            line))

        elif self.smtp_session_data:
            # Track how long a request takes
            _start_time = time.time()

            # Gather data at RCPT , data will be used at END-OF-MESSAGE
            _instance = self.smtp_session_data['instance']
            _protocol_state = self.smtp_session_data['protocol_state']

            if _protocol_state == 'RCPT':
                try:
                    _db = self.db_conns['conn_tracking']
                    _c = _db.cursor()
                    _c.execute(
                        "SELECT * FROM tracking WHERE instance=? LIMIT 1",
                        (_instance, ))
                    _row = _c.fetchone()
                    if _row:
                        logger.debug(
                            "Update `num_processed` for existing instance {}".
                            format(_instance))
                        _c.execute(
                            "UPDATE tracking set num_processed=num_processed+1 WHERE instance=?",
                            (_instance, ))
                    else:
                        logger.debug(
                            "Add new tracking record for instance {}".format(
                                _instance))
                        _c.execute(
                            "INSERT INTO tracking (instance, num_processed, init_time) values (?, ?, ?)",
                            (_instance, 0, int(time.time())))
                except Exception as e:
                    logger.error(
                        "while adding or updating existing tracking record: {}"
                        .format(repr(e)))

            # Call modeler and apply plugins
            try:
                modeler = Modeler(conns=self.db_conns)
                result = modeler.handle_data(
                    smtp_session_data=self.smtp_session_data,
                    plugins=self.plugins,
                    sender_search_attrlist=self.sender_search_attrlist,
                    recipient_search_attrlist=self.recipient_search_attrlist,
                )

                if result:
                    action = result
                else:
                    action = SMTP_ACTIONS['default']
                    logger.error(
                        "No result returned by modeler, fallback to default action: {}."
                        .format(action))

            except Exception as e:
                action = SMTP_ACTIONS['default']
                logger.error(
                    "Unexpected error: {}. Fallback to default action: {}".
                    format(repr(e), action))

            # Remove tracking data when:
            #
            #   - session was rejected/discard/whitelisted ('OK') during
            #     RCPT state (it never reach END-OF-MESSAGE state)
            #   - session is in last state (END-OF-MESSAGE)
            if (not action.startswith('DUNNO')) or (_protocol_state
                                                    == 'END-OF-MESSAGE'):
                # Remove expired tracking data.
                try:
                    _db = self.db_conns['conn_tracking']
                    _c = _db.cursor()

                    _expired_time = int(
                        time.time()) + settings.TRACKING_EXPIRE_SECONDS
                    _c.execute("DELETE FROM tracking WHERE init_time <=?",
                               (_expired_time, ))
                except Exception as e:
                    logger.error(
                        "while cleaning up expired tracking record: {}".format(
                            repr(e)))

            self.push('action=' + action + '\n')
            logger.debug("Session ended.")

            _end_time = time.time()
            utils.log_policy_request(smtp_session_data=self.smtp_session_data,
                                     action=action,
                                     start_time=_start_time,
                                     end_time=_end_time)

            # Log smtp session.
            # Postfix may send the smtp session data twice or even more if
            # iRedAPD is called in multiple protocol states, try to avoid
            # "duplicate" logging here.
            if _protocol_state == 'END-OF-MESSAGE' or \
               (_protocol_state == 'RCPT' and not action.startswith('DUNNO')):
                utils.log_smtp_session(conn=self.db_conns['conn_iredapd'],
                                       smtp_action=action,
                                       **self.smtp_session_data)
        else:
            action = SMTP_ACTIONS['default']
            logger.debug("replying: {}".format(action))
            self.push('action=' + action + '\n')
            logger.debug("Session ended")