Update of /cvsroot/tmda/tmda/bin
In directory usw-pr-cvs1:/tmp/cvs-serv31685/bin

Modified Files:
        tmda-ofmipd 
Log Message:
Add support for LDAP authentication.

Patch contributed by David Guerizec in
<[EMAIL PROTECTED]> on tmda-workers.


Index: tmda-ofmipd
===================================================================
RCS file: /cvsroot/tmda/tmda/bin/tmda-ofmipd,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- tmda-ofmipd 4 Sep 2002 03:08:51 -0000       1.15
+++ tmda-ofmipd 4 Sep 2002 23:54:36 -0000       1.16
@@ -56,16 +56,21 @@
        domain name for the local host).
 
     -R proto[://host[:port]]
-    --remoteauth proto[://host[:port]]
+    --remoteauth proto[://host[:port]][/dn]
         Host to connect to to check username and password.
         - proto can be one of the following:
          `imap' (IMAP4 server)
          'imaps' (IMAP4 server over SSL)
          `pop3' (POP3 server)
          `apop' (POP3 server with APOP authentication)
+         `ldap' (LDAP server)
         - host defaults to localhost
-        - port defaults to 143 (imap), 993 (imaps) or 110 (pop3/apop)
-        Example: -R imaps://myimapserver.net
+        - port defaults to 143 (imap), 993 (imaps), 110 (pop3/apop), 389 (ldap)
+        - dn is mandatory for ldap and should contain a `%%s' identifying
+          the username
+        Examples: -R imaps://myimapserver.net
+                  -R pop3://mypopserver.net:2110
+                  -R ldap://host.com/cn=%%s,dc=host,dc=com
 
     -A <program>
     --authprog <program>
@@ -127,12 +132,14 @@
 remoteauth = { 'proto': None,
                'host':  'localhost',
                'port':  None,
+               'dn':  '',
                'enable': 0,
                }
 defaultauthports = { 'imap':  143,
                      'imaps': 993,
                      'apop': 110,
                      'pop3':  110,
+                     'ldap':  389,
                      #                     'pop3s': 995,
                      }
 connections = 20
@@ -222,6 +229,11 @@
                     '\nPlease pick one of ' + repr(defaultauthports.keys())
         if arg:
             try:
+                arg, dn = arg.split('/', 1)
+                remoteauth['dn'] = dn
+            except ValueError:
+                dn = ''
+            try:
                 authhost, authport = arg.split(':', 1)
             except ValueError:
                 authhost = arg
@@ -230,8 +242,9 @@
                 remoteauth['host'] = authhost
             if authport:
                 remoteauth['port'] = authport
-        print >> DEBUGSTREAM, "auth method: %s://%s:%s" % \
-              (remoteauth['proto'], remoteauth['host'], remoteauth['port'])
+        print >> DEBUGSTREAM, "auth method: %s://%s:%s/%s" % \
+              (remoteauth['proto'], remoteauth['host'],
+               remoteauth['port'], remoteauth['dn'])
         remoteauth['enable'] = 1
     elif opt in ('-A', '--authprog'):
        authprog = arg
@@ -259,44 +272,6 @@
 COMMASPACE = ', '
 
 
-# Utility functions
-def pipecmd(command, *strings):
-    popen2._cleanup()
-    cmd = popen2.Popen3(command, 1, bufsize=-1)
-    cmdout, cmdin, cmderr = cmd.fromchild, cmd.tochild, cmd.childerr
-    if strings:
-        # Write to the tochild file object.
-        for s in strings:
-            cmdin.write(s)
-        cmdin.flush()
-        cmdin.close()
-    # Read from the childerr object; command will block until exit.
-    err = cmderr.read().strip()
-    cmderr.close()
-    # Read from the fromchild object.
-    out = cmdout.read().strip()
-    cmdout.close()
-    # Get exit status from the wait() member function.
-    return cmd.wait()
-
-
-def run_authprog(username, password):
-    """authprog should return 0 for auth ok, and a positive integer in
-    case of a problem."""
-    print >> DEBUGSTREAM, "Trying authprog method"
-    return pipecmd('%s' % authprog, '%s\0%s\0' % (username, password))
-
-
-def quote_rcpts(rcpttos):
-    """Each address should be properly quoted to prevent malicious
-    users from executing code by passing args to tmda-inject."""
-    rcpttos_quoted = []
-    for rcptto in rcpttos:
-        rcpttos_quoted.append("'%s'" %
-                              rcptto.replace
-                              ("\\", "\\\\").replace("'", "'\\\\\\''"))
-    return rcpttos_quoted
-
 if remoteauth['proto'] == 'imaps':
     vmaj, vmin = sys.version_info[:2]
     # Python version 2.2 and before don't have IMAP4_SSL
@@ -344,11 +319,68 @@
     else:
         IMAP4_SSL = imaplib.IMAP4_SSL
 
+if remoteauth['proto'] == 'ldap':
+    try:
+        import ldap
+    except ImportError:
+        raise ImportError, \
+              'python-ldap (http://python-ldap.sf.net/) required.'
+    if remoteauth['dn'] == '':
+        print >> DEBUGSTREAM, "Error: Missing ldap dn\n"
+        raise ValueError
+    try:
+        remoteauth['dn'].index('%s')
+    except:
+        print >> DEBUGSTREAM, "Error: Invalid ldap dn\n"
+        raise ValueError
+
+
+# Utility functions
+def pipecmd(command, *strings):
+    popen2._cleanup()
+    cmd = popen2.Popen3(command, 1, bufsize=-1)
+    cmdout, cmdin, cmderr = cmd.fromchild, cmd.tochild, cmd.childerr
+    if strings:
+        # Write to the tochild file object.
+        for s in strings:
+            cmdin.write(s)
+        cmdin.flush()
+        cmdin.close()
+    # Read from the childerr object; command will block until exit.
+    err = cmderr.read().strip()
+    cmderr.close()
+    # Read from the fromchild object.
+    out = cmdout.read().strip()
+    cmdout.close()
+    # Get exit status from the wait() member function.
+    return cmd.wait()
+
+
+def run_authprog(username, password):
+    """authprog should return 0 for auth ok, and a positive integer in
+    case of a problem."""
+    print >> DEBUGSTREAM, "Trying authprog method"
+    return pipecmd('%s' % authprog, '%s\0%s\0' % (username, password))
+
+
+def quote_rcpts(rcpttos):
+    """Each address should be properly quoted to prevent malicious
+    users from executing code by passing args to tmda-inject."""
+    rcpttos_quoted = []
+    for rcptto in rcpttos:
+        rcpttos_quoted.append("'%s'" %
+                              rcptto.replace
+                              ("\\", "\\\\").replace("'", "'\\\\\\''"))
+    return rcpttos_quoted
+
 
 def run_remoteauth(username, password):
-    print >> DEBUGSTREAM, "trying %s connection to %s@%s:%s" % \
-            (remoteauth['proto'], username, remoteauth['host'],
-             remoteauth['port'])
+    """Authenticate username/password combination against a remote
+    resource.  Return 1 upon successful authentication, and 0
+    otherwise."""
+    print >> DEBUGSTREAM, "trying %s authentication for %s@%s:%s" % \
+          (remoteauth['proto'], username, remoteauth['host'],
+           remoteauth['port'])
     port = defaultauthports[remoteauth['proto']]
     if remoteauth['proto'] == 'imap':
         import imaplib
@@ -360,7 +392,7 @@
             M.logout()
             return 1
         except:
-            print >> DEBUGSTREAM, "imap connection to %s@%s failed" % \
+            print >> DEBUGSTREAM, "imap authentication for %s@%s failed" % \
                   (username, remoteauth['host'])
             return 0
     elif remoteauth['proto'] == 'imaps':
@@ -373,7 +405,7 @@
             M.logout()
             return 1
         except:
-            print >> DEBUGSTREAM, "imaps connection to %s@%s failed" % \
+            print >> DEBUGSTREAM, "imaps authentication for %s@%s failed" % \
                   (username, remoteauth['host'])
             return 0
     elif remoteauth['proto'] in ('pop3', 'apop'):
@@ -392,11 +424,25 @@
                 M.quit()
                 return 1
         except:
-            print >> DEBUGSTREAM, "pop3 connection to %s@%s failed" % \
+            print >> DEBUGSTREAM, "%s authentication for %s@%s failed" % \
+                  (remoteauth['proto'], username, remoteauth['host'])
+            return 0
+    elif remoteauth['proto'] == 'ldap':
+        import ldap
+        if remoteauth['port']:
+            port = int(remoteauth['port'])
+        try:
+            M = ldap.initialize("ldap://%s:%s"; % (remoteauth['host'],
+                                                  remoteauth['port']))
+            M.simple_bind_s(remoteauth['dn'] % username, password)
+            M.unbind_s()
+            return 1
+        except:
+            print >> DEBUGSTREAM, "ldap authentication for %s@%s failed" % \
                   (username, remoteauth['host'])
             return 0
     # proto not implemented
-    print >> DEBUGSTREAM, "Error: protocole %s not implemented" % \
+    print >> DEBUGSTREAM, "Error: protocol %s not implemented" % \
             remoteauth['proto']
     return 0
 

_______________________________________
tmda-cvs mailing list
http://tmda.net/lists/listinfo/tmda-cvs

Reply via email to