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