Zhang Huangbin avatar Zhang Huangbin committed f0e8ba4

Code cleanup.

Comments (0)

Files changed (9)

src/iredapd-rr.py

 
 __version__ = '1.3.7'
 
-ACTION_ACCEPT = 'DUNNO'
-ACTION_DEFER = 'DEFER_IF_PERMIT Service temporarily unavailable'
-ACTION_REJECT = 'REJECT Permission denied'
-ACTION_DEFAULT = 'DUNNO'
+SMTP_ACTIONS['defer'] = 'DEFER_IF_PERMIT Service temporarily unavailable'
 
 PLUGIN_DIR = os.path.abspath(os.path.dirname(__file__)) + '/plugins-rr'
 sys.path.append(PLUGIN_DIR)
 cfg = ConfigParser.SafeConfigParser()
 cfg.read(config_file)
 
+from libs import __version__, SMTP_ACTIONS
 
 class apdChannel(asynchat.async_chat):
     def __init__(self, conn, remoteaddr):
                 if result != None:
                     action = result
                 else:
-                    action = ACTION_ACCEPT
+                    action = SMTP_ACTIONS['accept']
                 logging.debug("Final action: %s." % str(result))
             except Exception, e:
-                action = ACTION_DEFAULT
+                action = SMTP_ACTIONS['default']
                 logging.debug('Error: %s. Use default action instead: %s' %
                         (str(e), str(action)))
 
             asynchat.async_chat.handle_close(self)
             logging.debug("Connection closed")
         else:
-            action = ACTION_DEFER
+            action = SMTP_ACTIONS['defer']
             logging.debug("replying: " + action)
             self.push(action)
             self.push('')
                 # No plugins available.
                 return 'DUNNO'
         else:
-            return ACTION_DEFER
+            return SMTP_ACTIONS['defer']
 
 
 
                 # Return if recipient account doesn't exist.
                 if senderDN is None or senderLdif is None:
                     logging.debug('Sender DN or LDIF is none.')
-                    return ACTION_DEFAULT
+                    return SMTP_ACTIONS['default']
 
                 #
                 # Import plugin modules.
                 # No plugins available.
                 return 'DUNNO'
         else:
-            return ACTION_DEFER
+            return SMTP_ACTIONS['defer']
 
 
 def main():
 import logging
 import daemon
 
-__version__ = '1.3.7'
-
-ACTION_ACCEPT = 'DUNNO'
-ACTION_DEFER = 'DEFER_IF_PERMIT Service temporarily unavailable'
-ACTION_REJECT = 'REJECT Permission denied'
-ACTION_DEFAULT = 'DUNNO'
-
 PLUGIN_DIR = os.path.abspath(os.path.dirname(__file__)) + '/plugins'
 sys.path.append(PLUGIN_DIR)
 
 # Read configurations.
 cfg = ConfigParser.SafeConfigParser()
 cfg.read(config_file)
+backend = cfg.get('general', 'backend', 'ldap')
+
+if backend == 'ldap':
+    from libs.ldaplib import LDAPModeler as Modeler
+elif backend in ['mysql', 'pgsql']:
+    from libs.sqllib import SQLModeler as Modeler
+else:
+    sys.exit('Invalid backend. It should be ldap or sql.')
+
+from libs import __version__, SMTP_ACTIONS
 
 
 class apdChannel(asynchat.async_chat):
                 value = line.split('=', 1)[1]
                 self.map[key] = value
         elif len(self.map) != 0:
-            self.backend = cfg.get('general', 'backend', 'ldap')
             try:
-                if self.backend == 'ldap':
-                    modeler = LDAPModeler()
-                else:
-                    modeler = SQLModeler()
+                modeler = Modeler(cfg=cfg, logger=logging)
 
                 result = modeler.handle_data(self.map)
                 if result != None:
                     action = result
                 else:
-                    action = ACTION_ACCEPT
+                    action = SMTP_ACTIONS['accept']
                 logging.debug("Final action: %s." % str(result))
             except Exception, e:
-                action = ACTION_DEFAULT
+                action = SMTP_ACTIONS['default']
                 logging.debug('Error: %s. Use default action instead: %s' %
                         (str(e), str(action)))
 
             asynchat.async_chat.handle_close(self)
             logging.debug("Connection closed")
         else:
-            action = ACTION_DEFER
+            action = SMTP_ACTIONS['defer']
             logging.debug("replying: " + action)
             self.push(action)
             self.push('')
         channel = apdChannel(conn, remoteaddr)
 
 
-class SQLModeler:
-    def handle_data(self, map):
-        if 'sender' in map.keys() and 'recipient' in map.keys():
-            if len(map['sender']) < 6:
-                # Not a valid email address.
-                return 'DUNNO'
-
-            # Get plugin module name and convert plugin list to python list type.
-            self.plugins = cfg.get('sql', 'plugins', '')
-            self.plugins = [v.strip() for v in self.plugins.split(',')]
-
-            # Get sender, recipient.
-            # Sender/recipient are used almost in all plugins, so store them
-            # a dict and pass to plugins.
-            senderReceiver = {
-                'sender': map['sender'],
-                'recipient': map['recipient'],
-                'sender_domain': map['sender'].split('@')[-1],
-                'recipient_domain': map['recipient'].split('@')[-1],
-            }
-
-            if len(self.plugins) > 0:
-                #
-                # Import plugin modules.
-                #
-                self.modules = []
-
-                # Load plugin module.
-                for plugin in self.plugins:
-                    try:
-                        self.modules.append(__import__(plugin))
-                    except ImportError:
-                        # Print error message if plugin module doesn't exist.
-                        # Use logging.info to let admin know this critical error.
-                        logging.info('Error: plugin %s/%s.py not exist.' % (PLUGIN_DIR, plugin))
-                    except Exception, e:
-                        logging.debug('Error while importing plugin module (%s): %s' % (plugin, str(e)))
-
-                #
-                # Apply plugins.
-                #
-                self.action = ''
-                for module in self.modules:
-                    try:
-                        logging.debug('Apply plugin (%s).' % (module.__name__, ))
-                        if cfg.get('general', 'backend', 'ldap') == 'mysql':
-                            import MySQLdb
-                            try:
-                                db = MySQLdb.connect(
-                                    host=cfg.get('sql', 'server', 'localhost'),
-                                    db=cfg.get('sql', 'db', 'vmail'),
-                                    user=cfg.get('sql', 'user', 'vmail'),
-                                    passwd=cfg.get('sql', 'password'),
-                                )
-                                cursor = db.cursor()
-                            except Exception, e:
-                                logging.error("Error while creating database connection: %s" % str(e))
-                        elif cfg.get('general', 'backend', 'ldap') == 'pgsql':
-                            import psycopg2
-                            try:
-                                db = psycopg2.connect(
-                                    host=cfg.get('sql', 'server', 'localhost'),
-                                    port=cfg.get('sql', 'port', '5432'),
-                                    database=cfg.get('sql', 'db', 'vmail'),
-                                    user=cfg.get('sql', 'user', 'vmail'),
-                                    password=cfg.get('sql', 'password'),
-                                )
-                                cursor = db.cursor()
-                            except Exception, e:
-                                logging.error("Error while creating database connection: %s" % str(e))
-                        else:
-                            return ACTION_DEFAULT
-
-                        pluginAction = module.restriction(
-                            dbConn=cursor,
-                            senderReceiver=senderReceiver,
-                            smtpSessionData=map,
-                            logger=logging,
-                        )
-
-                        try:
-                            cursor.close()
-                            logging.debug('Closed SQL connection.')
-                        except Exception, e:
-                            logging.debug('Error while closing connection: %s' % str(e))
-
-                        logging.debug('Response from plugin (%s): %s' % (module.__name__, pluginAction))
-                        if not pluginAction.startswith('DUNNO'):
-                            logging.info('Response from plugin (%s): %s' % (module.__name__, pluginAction))
-                            return pluginAction
-                    except Exception, e:
-                        logging.debug('Error while apply plugin (%s): %s' % (module, str(e)))
-
-            else:
-                # No plugins available.
-                return 'DUNNO'
-        else:
-            return ACTION_DEFER
-
-
-class LDAPModeler:
-    def __init__(self):
-        import ldap
-
-        self.ldap = ldap
-
-        # Read LDAP server settings.
-        self.uri = cfg.get('ldap', 'uri', 'ldap://127.0.0.1:389')
-        self.binddn = cfg.get('ldap', 'binddn')
-        self.bindpw = cfg.get('ldap', 'bindpw')
-        self.baseDN = cfg.get('ldap', 'basedn')
-
-        # Initialize ldap connection.
-        try:
-            self.conn = self.ldap.initialize(self.uri)
-            logging.debug('LDAP connection initialied success.')
-        except Exception, e:
-            logging.error('LDAP initialized failed: %s.' % str(e))
-            sys.exit()
-
-        # Bind to ldap server.
-        if self.binddn != '' and self.bindpw != '':
-            try:
-                self.conn.bind_s(self.binddn, self.bindpw)
-                logging.debug('LDAP bind success.')
-            except self.ldap.INVALID_CREDENTIALS:
-                logging.error('LDAP bind failed: incorrect bind dn or password.')
-                sys.exit()
-            except Exception, e:
-                logging.error('LDAP bind failed: %s.' % str(e))
-                sys.exit()
-
-    def __get_recipient_dn_ldif(self, recipient):
-        logging.debug('__get_recipient_dn_ldif (recipient): %s' % recipient)
-        try:
-            filter = '(&(|(mail=%s)(shadowAddress=%s))(|(objectClass=mailUser)(objectClass=mailList)(objectClass=mailAlias)))' % (recipient, recipient)
-            logging.debug('__get_recipient_dn_ldif (ldap query filter): %s' % filter)
-
-            result = self.conn.search_s(self.baseDN, self.ldap.SCOPE_SUBTREE, filter)
-
-            if len(result) == 1:
-                logging.debug('__get_recipient_dn_ldif (ldap query result): %s' % str(result))
-                dn, entry = result[0]
-                return (dn, entry)
-            else:
-                logging.debug('__get_recipient_dn_ldif: Can not find recipient in LDAP server.')
-                return (None, None)
-        except Exception, e:
-            logging.debug('!!! ERROR !!! __get_recipient_dn_ldif (result): %s' % str(e))
-            return (None, None)
-
-    def __get_access_policy(self, recipient):
-        """Get access policy of mail list.
-
-        return (dn_of_mail_list, value_of_access_policy,)"""
-
-        logging.debug('__get_access_policy (list): %s' % recipient)
-
-        # Replace 'recipient' placehold in config file with mail list address.
-        try:
-            cfg.set('ldap', "recipient", recipient)
-        except Exception, e:
-            logging.error("""Error while replacing 'recipient': %s""" % (str(e)))
-
-        # Search mail list object.
-        searchBasedn = 'mail=%s,ou=Groups,domainName=%s,%s' % (recipient, recipient.split('@')[1], self.baseDN)
-        searchScope = self.ldap.SCOPE_BASE
-        searchFilter = cfg.get('ldap', 'filter_maillist')
-        searchAttr = cfg.get('ldap', 'attr_access_policy', 'accessPolicy')
-
-        logging.debug('__get_access_policy (searchBasedn): %s' % searchBasedn)
-        logging.debug('__get_access_policy (searchScope): %s' % searchScope)
-        logging.debug('__get_access_policy (searchFilter): %s' % searchFilter)
-        logging.debug('__get_access_policy (searchAttr): %s' % searchAttr)
-
-        try:
-            result = self.conn.search_s(searchBasedn, searchScope, searchFilter, [searchAttr])
-            logging.debug('__get_access_policy (search result): %s' % str(result))
-        except self.ldap.NO_SUCH_OBJECT:
-            logging.debug('__get_access_policy (not a mail list: %s) Returned (None)' % recipient)
-            return (None, None)
-        except Exception, e:
-            logging.debug('__get_access_policy (ERROR while searching list): %s' % str(e))
-            return (None, None)
-
-        if len(result) != 1:
-            return (None, None)
-        else:
-            # Example of result data:
-            # [('dn', {'accessPolicy': ['value']})]
-            listdn = result[0][0]
-            listpolicy = result[0][1][searchAttr][0]
-            returnVal = (listdn, listpolicy)
-
-            logging.debug('__get_access_policy (returned): %s' % str(returnVal))
-            return returnVal
-
-    def __get_allowed_senders(self, listdn, recipient, listpolicy, sender=''):
-        """return search_result_list_based_on_access_policy"""
-        logging.debug('__get_allowed_senders (listpolicy): %s' % listpolicy)
-
-        # Replace 'recipient' and 'sender' with email addresses.
-        cfg.set("ldap", "recipient", recipient)
-        cfg.set("ldap", "sender", sender)
-
-        # Set search base dn, scope, filter and attribute list based on access policy.
-        if listpolicy == 'membersOnly':
-            baseDN = self.baseDN
-            searchScope = self.ldap.SCOPE_SUBTREE
-            # Filter used to get domain members.
-            searchFilter = cfg.get("ldap", "filter_member")
-            searchAttr = cfg.get("ldap", "attr_member")
-        else:
-            baseDN = listdn
-            searchScope = self.ldap.SCOPE_BASE   # Use SCOPE_BASE to improve performance.
-            # Filter used to get domain moderators.
-            searchFilter = cfg.get("ldap", "filter_allowed_senders")
-            searchAttr = cfg.get("ldap", "attr_moderator")
-
-        logging.debug('__get_allowed_senders (baseDN): %s' % baseDN)
-        logging.debug('__get_allowed_senders (searchScope): %s' % searchScope)
-        logging.debug('__get_allowed_senders (searchFilter): %s' % searchFilter)
-        logging.debug('__get_allowed_senders (searchAttr): %s' % searchAttr)
-
-        try:
-            result = self.conn.search_s(baseDN, searchScope, searchFilter, [searchAttr])
-            logging.debug('__get_allowed_senders (search result): %s' % str(result))
-        except self.ldap.NO_SUCH_OBJECT:
-            logging.debug('__get_allowed_senders (not a mail list: %s) Returned (None)' % recipient)
-            return None
-        except Exception, e:
-            logging.debug('__get_allowed_senders (ERROR while searching list): %s' % str(e))
-            return None
-
-        if len(result) != 1:
-            return None
-        else:
-            # Example of result data:
-            # [('dn', {'listAllowedUser': ['user@domain.ltd']})]
-            return result[0][1][searchAttr]
-
-    def __get_smtp_action(self, recipient, sender):
-        """return smtp_action"""
-        listdn, listpolicy = self.__get_access_policy(recipient)
-
-        if listdn is None or listpolicy is None:
-            return None
-        else:
-            if listpolicy == "public":
-                # No restriction.
-                return ACTION_ACCEPT
-            elif listpolicy == "domain":
-                # Allow all users under the same domain.
-                if sender.split('@')[1] == recipient.split('@')[1]:
-                    return ACTION_ACCEPT
-                else:
-                    return ACTION_REJECT
-            elif listpolicy == "allowedOnly":
-                # Bypass allowed users only.
-                allowed_senders = self.__get_allowed_senders(listdn, recipient, 'allowedOnly', sender)
-
-                if allowed_senders is not None:
-                    addresses = set(allowed_senders)    # Remove duplicate addresses.
-                    if sender in addresses:
-                        return ACTION_ACCEPT
-                    else:
-                        return ACTION_REJECT
-                else:
-                    return ACTION_REJECT
-            elif listpolicy == "membersOnly":
-                allowed_senders = self.__get_allowed_senders(listdn, recipient, 'membersOnly', sender)
-
-                if allowed_senders is not None:
-                    addresses = set(allowed_senders)
-                    if sender in addresses:
-                        return ACTION_ACCEPT
-                    else:
-                        return ACTION_REJECT
-                else:
-                    #return ACTION_DEFER
-                    return ACTION_REJECT
-
-    def handle_data(self, map):
-        if 'sender' in map.keys() and 'recipient' in map.keys():
-            if len(map['sender']) < 6:
-                # Not a valid email address.
-                return 'DUNNO'
-
-            # Get plugin module name and convert plugin list to python list type.
-            self.plugins = cfg.get('ldap', 'plugins', '')
-            self.plugins = [v.strip() for v in self.plugins.split(',')]
-
-            if len(self.plugins) > 0:
-
-                # Get account dn and LDIF data.
-                recipientDn, recipientLdif = self.__get_recipient_dn_ldif(map['recipient'])
-
-                # Return if recipient account doesn't exist.
-                if recipientDn is None or recipientLdif is None:
-                    logging.debug('Recipient DN or LDIF is None.')
-                    return ACTION_DEFAULT
-
-                #
-                # Import plugin modules.
-                #
-                self.modules = []
-
-                # Load plugin module.
-                for plugin in self.plugins:
-                    try:
-                        self.modules.append(__import__(plugin))
-                    except ImportError:
-                        # Print error message if plugin module doesn't exist.
-                        # Use logging.info to let admin know this critical error.
-                        logging.info('Error: plugin %s/%s.py not exist.' % (PLUGIN_DIR, plugin))
-                    except Exception, e:
-                        logging.debug('Error while importing plugin module (%s): %s' % (plugin, str(e)))
-
-                #
-                # Apply plugins.
-                #
-                self.action = ''
-                for module in self.modules:
-                    try:
-                        logging.debug('Apply plugin (%s).' % (module.__name__, ))
-                        pluginAction = module.restriction(
-                            ldapConn=self.conn,
-                            ldapBaseDn=self.baseDN,
-                            ldapRecipientDn=recipientDn,
-                            ldapRecipientLdif=recipientLdif,
-                            smtpSessionData=map,
-                            logger=logging,
-                        )
-
-                        logging.debug('Response from plugin (%s): %s' % (module.__name__, pluginAction))
-                        if not pluginAction.startswith('DUNNO'):
-                            logging.info('Response from plugin (%s): %s' % (module.__name__, pluginAction))
-                            return pluginAction
-                    except Exception, e:
-                        logging.debug('Error while apply plugin (%s): %s' % (module, str(e)))
-
-            else:
-                # No plugins available.
-                return 'DUNNO'
-        else:
-            return ACTION_DEFER
-
-
 def main():
     # Set umask.
     os.umask(0077)

src/libs/__init__.py

+__version__ = '1.3.8'
+
+SMTP_ACTIONS = {'accept': 'DUNNO',
+                'defer': 'DEFER_IF_PERMIT Service temporarily unavailable',
+                'reject': 'REJECT Not authorized',
+                'default': 'DUNNO',
+               }

src/libs/ldaplib.py

+import sys
+import ldap
+from libs import SMTP_ACTIONS
+
+
+class LDAPModeler:
+    def __init__(self, cfg, logger):
+        self.cfg = cfg
+
+        # Read LDAP server related settings.
+        self.uri = self.cfg.get('ldap', 'uri', 'ldap://127.0.0.1:389')
+        self.binddn = self.cfg.get('ldap', 'binddn')
+        self.bindpw = self.cfg.get('ldap', 'bindpw')
+        self.baseDN = self.cfg.get('ldap', 'basedn')
+        self.logger = logger
+
+        # Initialize ldap connection.
+        try:
+            self.conn = ldap.initialize(self.uri)
+            self.logger.debug('LDAP connection initialied success.')
+        except Exception, e:
+            self.logger.error('LDAP initialized failed: %s.' % str(e))
+            sys.exit()
+
+        # Bind to ldap server.
+        try:
+            self.conn.bind_s(self.binddn, self.bindpw)
+            self.logger.debug('LDAP bind success.')
+        except ldap.INVALID_CREDENTIALS:
+            self.logger.error('LDAP bind failed: incorrect bind dn or password.')
+            sys.exit()
+        except Exception, e:
+            self.logger.error('LDAP bind failed: %s.' % str(e))
+            sys.exit()
+
+    def __del__(self):
+        try:
+            self.conn.unbind_s()
+            self.logger.debug('Close LDAP connection.')
+        except Exception, e:
+            self.logger.debug('Error while closing connection: %s' % str(e))
+
+    def __get_recipient_dn_ldif(self, recipient):
+        self.logger.debug('__get_recipient_dn_ldif (recipient): %s' % recipient)
+        try:
+            filter = '(&(|(mail=%s)(shadowAddress=%s))(|(objectClass=mailUser)(objectClass=mailList)(objectClass=mailAlias)))' % (recipient, recipient)
+            self.logger.debug('__get_recipient_dn_ldif (ldap query filter): %s' % filter)
+
+            result = self.conn.search_s(self.baseDN, ldap.SCOPE_SUBTREE, filter)
+
+            if len(result) == 1:
+                self.logger.debug('__get_recipient_dn_ldif (ldap query result): %s' % str(result))
+                dn, entry = result[0]
+                return (dn, entry)
+            else:
+                self.logger.debug('__get_recipient_dn_ldif: Can not find recipient in LDAP server.')
+                return (None, None)
+        except Exception, e:
+            self.logger.debug('!!! ERROR !!! __get_recipient_dn_ldif (result): %s' % str(e))
+            return (None, None)
+
+    def __get_access_policy(self, recipient):
+        """Get access policy of mail list.
+
+        return (dn_of_mail_list, value_of_access_policy,)"""
+
+        self.logger.debug('__get_access_policy (list): %s' % recipient)
+
+        # Replace 'recipient' placehold in config file with mail list address.
+        try:
+            self.cfg.set('ldap', "recipient", recipient)
+        except Exception, e:
+            self.logger.error("""Error while replacing 'recipient': %s""" % (str(e)))
+
+        # Search mail list object.
+        searchBasedn = 'mail=%s,ou=Groups,domainName=%s,%s' % (recipient, recipient.split('@')[1], self.baseDN)
+        searchScope = ldap.SCOPE_BASE
+        searchFilter = self.cfg.get('ldap', 'filter_maillist')
+        searchAttr = self.cfg.get('ldap', 'attr_access_policy', 'accessPolicy')
+
+        self.logger.debug('__get_access_policy (searchBasedn): %s' % searchBasedn)
+        self.logger.debug('__get_access_policy (searchScope): %s' % searchScope)
+        self.logger.debug('__get_access_policy (searchFilter): %s' % searchFilter)
+        self.logger.debug('__get_access_policy (searchAttr): %s' % searchAttr)
+
+        try:
+            result = self.conn.search_s(searchBasedn, searchScope, searchFilter, [searchAttr])
+            self.logger.debug('__get_access_policy (search result): %s' % str(result))
+        except ldap.NO_SUCH_OBJECT:
+            self.logger.debug('__get_access_policy (not a mail list: %s) Returned (None)' % recipient)
+            return (None, None)
+        except Exception, e:
+            self.logger.debug('__get_access_policy (ERROR while searching list): %s' % str(e))
+            return (None, None)
+
+        if len(result) != 1:
+            return (None, None)
+        else:
+            # Example of result data:
+            # [('dn', {'accessPolicy': ['value']})]
+            listdn = result[0][0]
+            listpolicy = result[0][1][searchAttr][0]
+            returnVal = (listdn, listpolicy)
+
+            self.logger.debug('__get_access_policy (returned): %s' % str(returnVal))
+            return returnVal
+
+    def __get_allowed_senders(self, listdn, recipient, listpolicy, sender=''):
+        """return search_result_list_based_on_access_policy"""
+        self.logger.debug('__get_allowed_senders (listpolicy): %s' % listpolicy)
+
+        # Replace 'recipient' and 'sender' with email addresses.
+        self.cfg.set("ldap", "recipient", recipient)
+        self.cfg.set("ldap", "sender", sender)
+
+        # Set search base dn, scope, filter and attribute list based on access policy.
+        if listpolicy == 'membersOnly':
+            baseDN = self.baseDN
+            searchScope = ldap.SCOPE_SUBTREE
+            # Filter used to get domain members.
+            searchFilter = self.cfg.get("ldap", "filter_member")
+            searchAttr = self.cfg.get("ldap", "attr_member")
+        else:
+            baseDN = listdn
+            searchScope = ldap.SCOPE_BASE   # Use SCOPE_BASE to improve performance.
+            # Filter used to get domain moderators.
+            searchFilter = self.cfg.get("ldap", "filter_allowed_senders")
+            searchAttr = self.cfg.get("ldap", "attr_moderator")
+
+        self.logger.debug('__get_allowed_senders (baseDN): %s' % baseDN)
+        self.logger.debug('__get_allowed_senders (searchScope): %s' % searchScope)
+        self.logger.debug('__get_allowed_senders (searchFilter): %s' % searchFilter)
+        self.logger.debug('__get_allowed_senders (searchAttr): %s' % searchAttr)
+
+        try:
+            result = self.conn.search_s(baseDN, searchScope, searchFilter, [searchAttr])
+            self.logger.debug('__get_allowed_senders (search result): %s' % str(result))
+        except ldap.NO_SUCH_OBJECT:
+            self.logger.debug('__get_allowed_senders (not a mail list: %s) Returned (None)' % recipient)
+            return None
+        except Exception, e:
+            self.logger.debug('__get_allowed_senders (ERROR while searching list): %s' % str(e))
+            return None
+
+        if len(result) != 1:
+            return None
+        else:
+            # Example of result data:
+            # [('dn', {'listAllowedUser': ['user@domain.ltd']})]
+            return result[0][1][searchAttr]
+
+    def __get_smtp_action(self, recipient, sender):
+        """return smtp_action"""
+        listdn, listpolicy = self.__get_access_policy(recipient)
+
+        if listdn is None or listpolicy is None:
+            return None
+        else:
+            if listpolicy == "public":
+                # No restriction.
+                return SMTP_ACTIONS['accept']
+            elif listpolicy == "domain":
+                # Allow all users under the same domain.
+                if sender.split('@')[1] == recipient.split('@')[1]:
+                    return SMTP_ACTIONS['accept']
+                else:
+                    return SMTP_ACTIONS['reject']
+            elif listpolicy == "allowedOnly":
+                # Bypass allowed users only.
+                allowed_senders = self.__get_allowed_senders(listdn, recipient, 'allowedOnly', sender)
+
+                if allowed_senders is not None:
+                    addresses = set(allowed_senders)    # Remove duplicate addresses.
+                    if sender in addresses:
+                        return SMTP_ACTIONS['accept']
+                    else:
+                        return SMTP_ACTIONS['reject']
+                else:
+                    return SMTP_ACTIONS['reject']
+            elif listpolicy == "membersOnly":
+                allowed_senders = self.__get_allowed_senders(listdn, recipient, 'membersOnly', sender)
+
+                if allowed_senders is not None:
+                    addresses = set(allowed_senders)
+                    if sender in addresses:
+                        return SMTP_ACTIONS['accept']
+                    else:
+                        return SMTP_ACTIONS['reject']
+                else:
+                    return SMTP_ACTIONS['reject']
+
+    def handle_data(self, map):
+        if 'sender' in map.keys() and 'recipient' in map.keys():
+            if len(map['sender']) < 6:
+                # Not a valid email address.
+                return 'DUNNO'
+
+            # Get plugin module name and convert plugin list to python list type.
+            self.plugins = self.cfg.get('ldap', 'plugins', '')
+            self.plugins = [v.strip() for v in self.plugins.split(',')]
+
+            if len(self.plugins) > 0:
+
+                # Get account dn and LDIF data.
+                recipientDn, recipientLdif = self.__get_recipient_dn_ldif(map['recipient'])
+
+                # Return if recipient account doesn't exist.
+                if recipientDn is None or recipientLdif is None:
+                    self.logger.debug('Recipient DN or LDIF is None.')
+                    return SMTP_ACTIONS['default']
+
+                #
+                # Import plugin modules.
+                #
+                self.modules = []
+
+                # Load plugin module.
+                for plugin in self.plugins:
+                    try:
+                        self.modules.append(__import__(plugin))
+                    except ImportError:
+                        # Print error message if plugin module doesn't exist.
+                        # Use self.logger.info to let admin know this critical error.
+                        self.logger.info('Error: plugin %s/%s.py not exist.' % (PLUGIN_DIR, plugin))
+                    except Exception, e:
+                        self.logger.debug('Error while importing plugin module (%s): %s' % (plugin, str(e)))
+
+                #
+                # Apply plugins.
+                #
+                self.action = ''
+                for module in self.modules:
+                    try:
+                        self.logger.debug('Apply plugin (%s).' % (module.__name__, ))
+                        pluginAction = module.restriction(
+                            ldapConn=self.conn,
+                            ldapBaseDn=self.baseDN,
+                            ldapRecipientDn=recipientDn,
+                            ldapRecipientLdif=recipientLdif,
+                            smtpSessionData=map,
+                            logger=self.logger,
+                        )
+
+                        self.logger.debug('Response from plugin (%s): %s' % (module.__name__, pluginAction))
+                        if not pluginAction.startswith('DUNNO'):
+                            self.logger.info('Response from plugin (%s): %s' % (module.__name__, pluginAction))
+                            return pluginAction
+                    except Exception, e:
+                        self.logger.debug('Error while apply plugin (%s): %s' % (module, str(e)))
+
+            else:
+                # No plugins available.
+                return 'DUNNO'
+        else:
+            return SMTP_ACTIONS['defer']
+

src/libs/sqllib.py

+from libs import SMTP_ACTIONS
+
+
+class SQLModeler:
+    def __init__(self, cfg, logger):
+        self.cfg = cfg
+        self.logger = logger
+
+        # Backend
+        self.backend = self.cfg.get('general', 'backend', 'mysql')
+
+        if self.backend == 'mysql':
+            import MySQLdb
+            try:
+                db = MySQLdb.connect(
+                    host=self.cfg.get('sql', 'server', 'localhost'),
+                    db=self.cfg.get('sql', 'db', 'vmail'),
+                    user=self.cfg.get('sql', 'user', 'vmail'),
+                    passwd=self.cfg.get('sql', 'password'),
+                )
+                self.cursor = db.cursor()
+            except Exception, e:
+                self.logger.error("Error while creating database connection: %s" % str(e))
+        elif self.backend == 'pgsql':
+            import psycopg2
+            try:
+                db = psycopg2.connect(
+                    host=self.cfg.get('sql', 'server', 'localhost'),
+                    port=self.cfg.get('sql', 'port', '5432'),
+                    database=self.cfg.get('sql', 'db', 'vmail'),
+                    user=self.cfg.get('sql', 'user', 'vmail'),
+                    password=self.cfg.get('sql', 'password'),
+                )
+                self.cursor = db.cursor()
+            except Exception, e:
+                self.logger.error("Error while creating database connection: %s" % str(e))
+        else:
+            return SMTP_ACTIONS['default']
+
+    def __del__(self):
+        try:
+            self.cursor.close()
+            self.logger.debug('Closed SQL connection.')
+        except Exception, e:
+            self.logger.debug('Error while closing connection: %s' % str(e))
+
+    def handle_data(self, map):
+        if 'sender' in map.keys() and 'recipient' in map.keys():
+            if len(map['sender']) < 6:
+                # Not a valid email address.
+                return 'DUNNO'
+
+            # Get plugin module name and convert plugin list to python list type.
+            self.plugins = self.cfg.get('sql', 'plugins', '')
+            self.plugins = [v.strip() for v in self.plugins.split(',')]
+
+            # Get sender, recipient.
+            # Sender/recipient are used almost in all plugins, so store them
+            # a dict and pass to plugins.
+            senderReceiver = {
+                'sender': map['sender'],
+                'recipient': map['recipient'],
+                'sender_domain': map['sender'].split('@')[-1],
+                'recipient_domain': map['recipient'].split('@')[-1],
+            }
+
+            if len(self.plugins) > 0:
+                #
+                # Import plugin modules.
+                #
+                self.modules = []
+
+                # Load plugin module.
+                for plugin in self.plugins:
+                    try:
+                        self.modules.append(__import__(plugin))
+                    except ImportError:
+                        # Print error message if plugin module doesn't exist.
+                        # Use self.logger.info to let admin know this critical error.
+                        self.logger.info('Error: plugin %s/%s.py not exist.' % (PLUGIN_DIR, plugin))
+                    except Exception, e:
+                        self.logger.debug('Error while importing plugin module (%s): %s' % (plugin, str(e)))
+
+                #
+                # Apply plugins.
+                #
+                self.action = ''
+                for module in self.modules:
+                    try:
+                        self.logger.debug('Apply plugin (%s).' % (module.__name__, ))
+                        pluginAction = module.restriction(
+                            dbConn=self.cursor,
+                            senderReceiver=senderReceiver,
+                            smtpSessionData=map,
+                            logger=self.logger,
+                        )
+
+                        self.logger.debug('Response from plugin (%s): %s' % (module.__name__, pluginAction))
+                        if not pluginAction.startswith('DUNNO'):
+                            self.logger.info('Response from plugin (%s): %s' % (module.__name__, pluginAction))
+                            return pluginAction
+                    except Exception, e:
+                        self.logger.debug('Error while apply plugin (%s): %s' % (module, str(e)))
+
+            else:
+                # No plugins available.
+                return 'DUNNO'
+        else:
+            return SMTP_ACTIONS['defer']
+

src/plugins/block_amavisd_blacklisted_senders.py

 # Author: Zhang Huangbin <zhb@iredmail.org>
 
-import sys
 import os
 
 PLUGIN_NAME = os.path.basename(__file__)

src/plugins/ldap_domain_wblist.py

 
 PLUGIN_NAME = os.path.basename(__file__)
 
-ACTION_REJECT = 'REJECT Permission denied'
-
 def restriction(ldapConn, ldapBaseDn, smtpSessionData, logger, **kargs):
     sender = smtpSessionData['sender'].lower()
     splitedSenderDomain = str(sender.split('@')[-1]).split('.')

src/plugins/ldap_maillist_access_policy.py

-#!/usr/bin/env python
-# encoding: utf-8
-
 # Author: Zhang Huangbin <zhb@iredmail.org>
 
 # ----------------------------------------------------------------------------
 # This plugin is used for mail deliver restriction.
 #
-# Handled policies:
+# Available access policies:
 #   - public:   Unrestricted
 #   - domain:   Only users under same domain are allowed.
 #   - subdomain:    Only users under same domain and sub domains are allowed.
 # ----------------------------------------------------------------------------
 
 import os
+from libs import SMTP_ACTIONS
 
-ACTION_REJECT = 'REJECT Permission denied'
 PLUGIN_NAME = os.path.basename(__file__)
 
 def __get_allowed_senders(ldapConn, ldapBaseDn, listDn, sender, recipient, policy, logger, *kw, **kargs):
         if sender_domain in recipient_alias_domains:
             return 'DUNNO Access policy: domain'
         else:
-            return ACTION_REJECT + ' Access policy: domain.'
+            return SMTP_ACTIONS['reject']
     elif policy == "subdomain":
         # Bypass all users under the same domain and sub domains.
         returned = False
                 return 'DUNNO Access policy: subdomain (%s)' % (d)
 
         if returned is False:
-            return ACTION_REJECT + ' Access policy: subdomain.'
+            return SMTP_ACTIONS['reject']
     else:
         # Handle other access policies: membersOnly, allowedOnly, membersAndModeratorsOnly.
         allowedSenders = __get_allowed_senders(
         if sender.lower() in [v.lower() for v in allowedSenders]:
             return 'DUNNO Allowed sender.'
         else:
-            return ACTION_REJECT
+            return SMTP_ACTIONS['reject']

src/plugins/sql_alias_access_policy.py

 #   - membersOnly:  Only members are allowed.
 #   - moderatorsOnly:   Only moderators are allowed.
 #   - membersAndModeratorsOnly: Only members and moderators are allowed.
-
 import os
 from web import sqlquote
+from libs import SMTP_ACTIONS
 
-ACTION_REJECT = 'REJECT Permission denied'
 PLUGIN_NAME = os.path.basename(__file__)
 
 # Policies. MUST be defined in lower case.
         if senderReceiver['sender_domain'] == senderReceiver['recipient_domain']:
             return 'DUNNO'
         else:
-            return ACTION_REJECT
+            return SMTP_ACTIONS['reject']
     elif policy == POLICY_SUBDOMAIN:
         # Bypass all users under the same domain or sub domains.
         if senderReceiver['sender'].endswith('.' + senderReceiver['recipient_domain']):
             return 'DUNNO'
         else:
-            return ACTION_REJECT
+            return SMTP_ACTIONS['reject']
     elif policy == POLICY_MEMBERSONLY:
         # Bypass all members.
         if senderReceiver['sender'] in members:
             return 'DUNNO'
         else:
-            return ACTION_REJECT
+            return SMTP_ACTIONS['reject']
     elif policy == POLICY_MODERATORSONLY or policy == POLICY_ALLOWEDONLY:
         # Bypass all moderators.
         if senderReceiver['sender'] in moderators:
             return 'DUNNO'
         else:
-            return ACTION_REJECT
+            return SMTP_ACTIONS['reject']
     elif policy == POLICY_MEMBERSANDMODERATORSONLY:
         # Bypass both members and moderators.
         if senderReceiver['sender'] in members or senderReceiver['sender'] in moderators:
             return 'DUNNO'
         else:
-            return ACTION_REJECT
+            return SMTP_ACTIONS['reject']
     else:
         # Bypass all if policy is not defined in this plugin.
         return 'DUNNO Policy is not defined in plugin (%s): %s.' % (PLUGIN_NAME, policy)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.