NoPaste

getmail-ldap.py

von sharbich
SNIPPET_DESC:
getmail-ldap.py
SNIPPET_CREATION_TIME:
30.04.2021 20:35:53
SNIPPET_PRUNE_TIME:
30.05.2021 20:35:53

SNIPPET_TEXT:
  1. secmail@dsme01:~$ cat getmail-ldap.py
  2. #!/usr/bin/python
  3. # File: getmail-ldap.py
  4. try:
  5.         import errno
  6.         import string
  7.         import logging
  8.         import logging.handlers
  9.         import ldap
  10.         import ConfigParser
  11.         import ldif
  12.         import threading
  13.         from StringIO import StringIO
  14.         from ldap.cidict import cidict
  15.         from os.path import os
  16.         from subprocess import Popen,PIPE
  17. except ImportError:
  18.         print """Cannot find all required libraries please install them and try again"""
  19.         raise SystemExit
  20.  
  21. config_file_location = '/home/secmail/getmail-ldap.cfg'
  22.  
  23. def pid_exists(pid):
  24.     """Is there a process with PID pid?"""
  25.     if pid < 0:
  26.         return False
  27.  
  28.     exist = False
  29.     try:
  30.         os.kill(pid, 0)
  31.         exist = 1
  32.     except OSError, x:
  33.         if x.errno != errno.ESRCH:
  34.             raise
  35.  
  36.     return exist
  37.  
  38. def get_search_results(results):
  39.     """Given a set of results, return a list of LDAPSearchResult
  40.    objects.
  41.    """
  42.     res = []
  43.  
  44.     if type(results) == tuple and len(results) == 2 :
  45.         (code, arr) = results
  46.     elif type(results) == list:
  47.         arr = results
  48.  
  49.     if len(results) == 0:
  50.         return res
  51.  
  52.     for item in arr:
  53.         res.append( LDAPSearchResult(item) )
  54.  
  55.     return res
  56.  
  57. class LDAPSearchResult:
  58.     """A class to model LDAP results.
  59.    """
  60.  
  61.     dn = ''
  62.  
  63.     def __init__(self, entry_tuple):
  64.         """Create a new LDAPSearchResult object."""
  65.         (dn, attrs) = entry_tuple
  66.         if dn:
  67.             self.dn = dn
  68.         else:
  69.             return
  70.  
  71.         self.attrs = cidict(attrs)
  72.  
  73.     def get_attributes(self):
  74.         """Get a dictionary of all attributes.
  75.        get_attributes()->{'name1':['value1','value2',...],
  76.                                 'name2: [value1...]}
  77.        """
  78.         return self.attrs
  79.  
  80.     def set_attributes(self, attr_dict):
  81.         """Set the list of attributes for this record.
  82.  
  83.        The format of the dictionary should be string key, list of
  84.        string alues. e.g. {'cn': ['M Butcher','Matt Butcher']}
  85.  
  86.        set_attributes(attr_dictionary)
  87.        """
  88.  
  89.         self.attrs = cidict(attr_dict)
  90.  
  91.     def has_attribute(self, attr_name):
  92.         """Returns true if there is an attribute by this name in the
  93.        record.
  94.  
  95.        has_attribute(string attr_name)->boolean
  96.        """
  97.         return self.attrs.has_key( attr_name )
  98.  
  99.     def get_attr_values(self, key):
  100.         """Get a list of attribute values.
  101.        get_attr_values(string key)->['value1','value2']
  102.        """
  103.         return self.attrs[key]
  104.  
  105.     def get_attr_names(self):
  106.         """Get a list of attribute names.
  107.        get_attr_names()->['name1','name2',...]
  108.        """
  109.         return self.attrs.keys()
  110.  
  111.     def get_dn(self):
  112.         """Get the DN string for the record.
  113.        get_dn()->string dn
  114.        """
  115.         return self.dn
  116.  
  117.     def pretty_print(self):
  118.         """Create a nice string representation of this object.
  119.  
  120.        pretty_print()->string
  121.        """
  122.         str = "DN: " + self.dn + "\n"
  123.         for a, v_list in self.attrs.iteritems():
  124.             str = str + "Name: " + a + "\n"
  125.             for v in v_list:
  126.                 str = str + "  Value: " + v + "\n"
  127.         str = str + "========"
  128.         return str
  129.  
  130.     def to_ldif(self):
  131.         """Get an LDIF representation of this record.
  132.  
  133.        to_ldif()->string
  134.        """
  135.         out = StringIO()
  136.         ldif_out = ldif.LDIFWriter(out)
  137.         ldif_out.unparse(self.dn, self.attrs)
  138.         return out.getvalue()
  139.  
  140. class RetrieveMails(threading.Thread):
  141.         def __init__(self, getmail_binary, config_filename, config_data_dir):
  142.                 threading.Thread.__init__(self)
  143.                 self.getmail_binary, self.config_filename, self.config_data_dir = \
  144.                         getmail_binary, config_filename, config_data_dir
  145.         def run(self):
  146.                 try:
  147.                         command = [self.getmail_binary, \
  148.                                 #'--quiet', \
  149.                                 '--rcfile=' + self.config_filename, \
  150.                                 '--getmaildir=' + self.config_data_dir]
  151.                         self.pid_filename = self.config_filename + '.pid'
  152.                         # Check for a pidfile to see if the daemon already runs
  153.                         try:
  154.                                 pid_file = file(self.pid_filename,'r')
  155.                                 pid_number = pid = int(pid_file.read().strip())
  156.                                 pid_file.close()
  157.                         except IOError:
  158.                                 pid = None
  159.                         # Check whether process is really running
  160.                         if pid:
  161.                                 pid = pid_exists(pid)
  162.                         if not pid:
  163.                                 getmail_process = Popen(command, shell=False,stdout=PIPE,stderr=PIPE)
  164.                                 try:
  165.                                         file(self.pid_filename,'w+').write("%s\n" % getmail_process.pid)
  166.                                         getmail_process.wait()
  167.                                 finally:
  168.                                         os.remove(self.pid_filename)
  169.                                         # Zur Sicherheit die erstellte Konfigurationsdatei loeschen (Login-Daten!)
  170.                                         os.remove(self.config_filename)
  171.                                 stderr_output=string.join(getmail_process.stderr.readlines())
  172.                                 if getmail_process.returncode <> 0 or len(stderr_output.strip())>0 :
  173.                                         raise Exception, "Getmail command failed for " + " ".join(command) \
  174.                                                 +"\nStdErr: \n" + string.join(stderr_output.strip()) \
  175.                                                 +"\nStdOut: \n" + string.join(getmail_process.stdout.readlines())
  176.                         else:
  177.                                 log_object.info("Command " + " ".join(command) +\
  178.                                         " not executed, existing pid " + str(pid_number) + " found")
  179.                 except:
  180.                         log_object.exception("An error occured!")
  181.  
  182. class RetrieveAccount:
  183.         account_name = None
  184.         account_type = None
  185.         login = None
  186.         password = None
  187.         server = None
  188.         def __init__(self, account_name=None, account_type=None, server=None, login=None, password=None):
  189.                 self.account_name, self.account_type, self.login, self.password, self.server = \
  190.                         account_name, account_type, login, password, server
  191.  
  192. class GetmailConfigFile(ConfigParser.SafeConfigParser):
  193.         output_filename = None
  194.         def __init__(self, defaults, default_config_filename=None, output_filename=None):
  195.                 ConfigParser.SafeConfigParser.__init__(self, defaults)
  196.                 if default_config_filename is not None:
  197.                         self.read(default_config_filename)
  198.                 self.output_filename = output_filename
  199.         def set_pop3_account(self, newRetrieveAccount):
  200.                 self.set('retriever','server',newRetrieveAccount.server)
  201.                 self.set('retriever','type',newRetrieveAccount.account_type)
  202.                 self.set('retriever','username',newRetrieveAccount.login)
  203.                 self.set('retriever','password',newRetrieveAccount.password)
  204.                 self.set('destination','arguments','("'+newRetrieveAccount.account_name+'",)')
  205.         def write(self):
  206.                 if self.output_filename is not None:
  207.                         """try:
  208.                                 output_file = open(self.output_filename, 'wb')
  209.                         except:
  210.                                 raise Exception, "Unable to open " + \
  211.                                         self.output_filename + "for writing"
  212.                         finally:
  213.                                 output_file.close()
  214.                         """
  215.                         os.umask(0077)
  216.                         output_file = open(self.output_filename, 'wb')
  217.                         ConfigParser.SafeConfigParser.write(self, output_file)
  218.                 else:
  219.                         raise Exception, "No output file for configuration defined"
  220.  
  221. # Konfigurationsdatei lesen
  222. config_object = ConfigParser.SafeConfigParser()
  223. config_object.read(config_file_location)
  224.  
  225. # Set-up Logging
  226. log_object = logging.getLogger("getmail-ldap")
  227. log_object.setLevel(logging.DEBUG)
  228.  
  229. # This handler writes everything to a log file.
  230. log_file_handler = logging.FileHandler(config_object.get('Logging','LogFile'))
  231. log_file_formatter = logging.Formatter("%(levelname)s %(asctime)s %(funcName)s %(lineno)d %(message)s")
  232. log_file_handler.setFormatter(log_file_formatter)
  233. log_file_handler.setLevel(logging.DEBUG)
  234. log_object.addHandler(log_file_handler)
  235.  
  236. # This handler emails anything that is an error or worse.
  237. log_smtp_handler = logging.handlers.SMTPHandler(\
  238.         config_object.get('Logging','MailServer'),\
  239.         config_object.get('Logging','MailFrom'),\
  240.         config_object.get('Logging','MailTo').split(','),\
  241.         config_object.get('Logging','MailSubject'))
  242. log_smtp_handler.setLevel(logging.ERROR)
  243. log_smtp_handler.setFormatter(log_file_formatter)
  244. log_object.addHandler(log_smtp_handler)
  245.  
  246. def main_call():
  247.  
  248.         ## first you must open a connection to the LDAP server
  249.         ldap_object = ldap.initialize(config_object.get('LDAP','LDAPServer'))
  250.         ldap_object.simple_bind_s(\
  251.                 config_object.get('LDAP','BindDN'),\
  252.                 config_object.get('LDAP','BindPassword'))
  253.         # searching doesn't require a bind in LDAP V3.
  254.         # If you're using LDAP v2, set the next line appropriately
  255.         # and do a bind as shown in the above example.
  256.         # you can also set this to ldap.VERSION2 if you're using a v2 directory
  257.         # you should  set the next option to ldap.VERSION2 if you're using a v2 directory
  258.         ldap_object.protocol_version = ldap.VERSION3
  259.  
  260.         ## The next lines will also need to be changed to support your search requirements and directory
  261.         ## retrieve all attributes - again adjust to your needs - see documentation for more options
  262.  
  263.         if config_object.get('LDAP','SearchScope').upper() == "SUB":
  264.             search_scope = ldap.SCOPE_SUBTREE
  265.         elif config_object.get('LDAP','SearchScope').upper() == "ONE":
  266.             search_scope = ldap.SCOPE_ONELEVEL
  267.         else:
  268.             search_scope = ldap.SCOPE_BASE
  269.  
  270.         ldap_result_id = ldap_object.search( \
  271.                 config_object.get('LDAP','SearchDN'), \
  272.                 search_scope,
  273.                 config_object.get('LDAP','SearchFilter'), \
  274.                 None)
  275.  
  276.         ldap_results = []
  277.  
  278.         while 1:
  279.                 result_type, result_data = ldap_object.result(ldap_result_id, 0)
  280.                 if (result_data == []):
  281.                         break
  282.                 else:
  283.                         ## here you don't have to append to a list
  284.                         ## you could do whatever you want with the individual entry
  285.                         ## The appending to list is just for illustration.
  286.                         if result_type == ldap.RES_SEARCH_ENTRY:
  287.                                 ldap_results += get_search_results(result_data)
  288.         for ldap_result in ldap_results:
  289.                 account = RetrieveAccount( \
  290.                         # Account Name \
  291.                         ldap_result.get_attr_values(\
  292.                                 config_object.get('LDAP','RelevantAttributes').split(',')[0])[0] ,\
  293.                         # Account Type \
  294.                         ldap_result.get_attr_values(\
  295.                                 config_object.get('LDAP','RelevantAttributes').split(',')[1])[0],\
  296.                         # Server \
  297.                         ldap_result.get_attr_values(\
  298.                                 config_object.get('LDAP','RelevantAttributes').split(',')[2])[0],\
  299.                         # Login \
  300.                         ldap_result.get_attr_values(\
  301.                                 config_object.get('LDAP','RelevantAttributes').split(',')[3])[0],\
  302.                         # Password \
  303.                         ldap_result.get_attr_values(\
  304.                                 config_object.get('LDAP','RelevantAttributes').split(',')[4])[0]\
  305.                 )
  306.                 config_output_filename = os.path.join(\
  307.                         config_object.get('Main','ConfigFileOutputDir'), \
  308.                         "getmail_" + \
  309.                         account.account_name + \
  310.                         ".cfg")
  311.                 config_file = GetmailConfigFile(None, \
  312.                         config_object.get('Main','DefaultGetmailConfigFile'), config_output_filename)
  313.                 config_file.set_pop3_account(account)
  314.                 log_object.info("Writing Account Configuration for " + account.account_name + \
  315.                                 " to file " + config_output_filename)
  316.                 config_file.write()
  317.                 RetrieveMails(\
  318.                         config_object.get('Main','GetmailBinary'), \
  319.                         config_output_filename, \
  320.                         config_object.get('Main','GetmailDir')\
  321.                 ).start()
  322.                 print config_output_filename
  323.                 print "Name " + account.account_name
  324.                 print "Type " + account.account_type
  325.                 print "Server " + account.server
  326.                 print "Login " + account.login
  327.                 print "Password " + account.password
  328.                 print "-----------------"
  329.                 print ldap_result.pretty_print()
  330.  
  331. if __name__ == "__main__":
  332.         try:
  333.                 main_call();
  334.         except:
  335.                 log_object.exception("An error occured!")

Quellcode

Hier kannst du den Code kopieren und ihn in deinen bevorzugten Editor einfügen. PASTEBIN_DOWNLOAD_SNIPPET_EXPLAIN