Hello all,

I've rolled up my own Debian packages with the latest cvs version. I've backported the patches discussed in an earlier post and i've also included my own external user lookup patch, which i also (re)submit here as attachment.

Those can be browsed directly here http://hmonteiro.net/repository:debian or just add the following lines to your /etc/apt/sources.list

#for etch
deb http://hmonteiro.net/debian sid .
deb-src http://hmonteiro.net/debian sid .

#for sid
deb http://hmonteiro.net/debian etch .
deb-src http://hmonteiro.net/debian etch .


For those not aware, this patch allows DSPAM to lookup in an external source, a username to be used in the dspam database. I find this very handy in at least two situations.

1 - The MTA doesn't support user lookups by it's own, making it hard/impossible to get all the matching address for single user so that the same DSPAM dictionary is used for all those matches.

2 - In some custom setups, there may be the need to have something used as DSPAM user address that is not either the login username or an email address. Situations were those values can change through the user account lifetime are more common every day. This may sound weird, but one could even have a windows SID as username in the DSPAM database.


How it works:

right after DSPAM is called, and right before it starts doing anything with the parameters, it will use an internal LDAP backend or an external program to preform a lookup with the value used in the --user (or calling uid if no --user was used) parameter. The backend/program will then return a value to be used instead of that one. The user parameter is then rewritten and that is what is used for the remaining operations.

This patch, as is, provides two different lookup backends right now:

A builtin LDAP lookup routine, similar in spirit to the existing ldap_client one, but it uses the latest LDAP API (no more #define LDAP_DEPRECATED 1). One other improvement, still using the LDAP backend, is the possibility to specify complex search filters like "(&(objectClass=qmailUser)(|(mail=%u)(mailAlternateAddress=%u)(uid=%u)))", allowing a much easier integration with retraining procedures since you can specify several test conditions that might not always be available with a single "(mail=%u)". It's also possible to specify LDAP bind credentials, for those not confortable with "world" readable directories, and it's also possible to use TLS for securing the LDAP connections. You can choose between LDAP protocol version 2 or 3, for legacy support, and it's also possible to specify an alternate LDAP port to connecto to.

A generic program lookup. DSPAM is able to call a custom script (bash, perl, python, C program, etc), to preform the lookup. The objective is the same as the above, but for those that don't use LDAP. The program/script takes as input one parameter and it returns a single line with a value. That returned value will be used in DSPAMs database.

At first i was thinking about a MySQL backend, but since i never had the need for one, and no one ever showed any interest in it, i just postponed the idea.

Let me also say that i find this feature very handy for mail relay machines, "a la" appliance type, where your main objective is to keep things as simple as can be.


Because all the above i'm submitting the patch for a possible inclusion. :)


Regards,

Hugo Monteiro.

--
ci.fct.unl.pt:~# cat .signature

Hugo Monteiro
Email    : [EMAIL PROTECTED]
Telefone : +351 212948300 Ext.15307

Centro de Informática
Faculdade de Ciências e Tecnologia da
                   Universidade Nova de Lisboa
Quinta da Torre   2829-516 Caparica   Portugal
Telefone: +351 212948596   Fax: +351 212948548
www.ci.fct.unl.pt             [EMAIL PROTECTED]

ci.fct.unl.pt:~# _

diff -Nru dspam/configure.ac dspam-extlookup/configure.ac
--- dspam/configure.ac  2008-02-01 20:13:52.000000000 +0000
+++ dspam-extlookup/configure.ac        2008-04-20 14:40:52.000000000 +0100
@@ -138,7 +138,7 @@
 #   Support for NodalCore(r) C-Series Hardware Extensions
 #
 DS_NCORE()
-DS_LDAP()
+DS_EXT_LOOKUP()
 
 AM_CONDITIONAL([BUILD_NCORE], [ test x$build_ncore = xyes ])
 
diff -Nru dspam/m4/external_lookup.m4 dspam-extlookup/m4/external_lookup.m4
--- dspam/m4/external_lookup.m4 1970-01-01 01:00:00.000000000 +0100
+++ dspam-extlookup/m4/external_lookup.m4       2008-04-20 14:40:52.000000000 
+0100
@@ -0,0 +1,38 @@
+# $Id: ldap.m4,v 1.1 2005/06/08 02:15:09 jonz Exp $
+# m4/external_lookup.m4
+# Hugo Monteiro <[EMAIL PROTECTED]>
+#
+#   DS_EXT_LOOKUP()
+#
+#   Activate external user lookup
+#
+AC_DEFUN([DS_EXT_LOOKUP],
+[
+
+  AC_ARG_ENABLE(external-lookup,
+      [AS_HELP_STRING(--enable-external-lookup,
+                        Enable external lookup support
+                      )])
+  AC_MSG_CHECKING([whether to enable external lookup support])
+  case x"$enable_external_lookup" in
+      xyes)   # external lookup enabled explicity
+              ;;
+      xno)    # external lookup disabled explicity
+              ;;
+      x)      # external lookup disabled by default
+              enable_external_lookup=no
+              ;;
+      *)      AC_MSG_ERROR([unexpected value $enable_external_lookup for 
--{enable,disable}-external-lookup configure option])
+              ;;
+  esac
+  if test x"$enable_external_lookup" != xyes
+  then
+      enable_external_lookup=no
+  else
+      enable_external_lookup=yes    # overkill, but convenient
+      AC_DEFINE(EXT_LOOKUP, 1, [Defined if external lookup is enabled])
+
+      LIBS="$LIBS -lldap -llber"
+  fi
+  AC_MSG_RESULT([$enable_external_lookup])
+])
diff -Nru dspam/m4/ldap.m4 dspam-extlookup/m4/ldap.m4
--- dspam/m4/ldap.m4    2005-06-08 03:15:09.000000000 +0100
+++ dspam-extlookup/m4/ldap.m4  1970-01-01 01:00:00.000000000 +0100
@@ -1,38 +0,0 @@
-# $Id: ldap.m4,v 1.1 2005/06/08 02:15:09 jonz Exp $
-# m4/ldap.m4
-# Jonathan A. Zdziarski <[EMAIL PROTECTED]>
-#
-#   DS_LDAP()
-#
-#   Activate libldap/liblber extensions from OpenLDAP
-#
-AC_DEFUN([DS_LDAP],
-[
-
-  AC_ARG_ENABLE(ldap,
-      [AS_HELP_STRING(--enable-ldap,
-                        Enable LDAP support via libldap
-                      )])
-  AC_MSG_CHECKING([whether to enable LDAP support])
-  case x"$enable_ldap" in
-      xyes)   # ldap enabled explicity
-              ;;
-      xno)    # ldap disabled explicity
-              ;;
-      x)      # ldap disabled by default
-              enable_ldap=no
-              ;;
-      *)      AC_MSG_ERROR([unexpected value $enable_ldap for 
--{enable,disable}-ldap configure option])
-              ;;
-  esac
-  if test x"$enable_ldap" != xyes
-  then
-      enable_ldap=no
-  else
-      enable_ldap=yes    # overkill, but convenient
-      AC_DEFINE(USE_LDAP, 1, [Defined if ldap is enabled])
-
-      LIBS="$LIBS -lldap -llber"
-  fi
-  AC_MSG_RESULT([$enable_ldap])
-])
diff -Nru dspam/m4/Makefile.am dspam-extlookup/m4/Makefile.am
--- dspam/m4/Makefile.am        2006-06-07 17:14:47.000000000 +0100
+++ dspam-extlookup/m4/Makefile.am      2008-04-20 14:40:52.000000000 +0100
@@ -10,6 +10,6 @@
        pgsql_drv.m4                            \
        sqlite_drv.m4                           \
        dllibs.m4                               \
-       ldap.m4                                 \
+       external_lookup.m4                      \
        pthread.m4                              \
        ncore.m4
diff -Nru dspam/src/dspam.c dspam-extlookup/src/dspam.c
--- dspam/src/dspam.c   2007-12-07 00:11:51.000000000 +0000
+++ dspam-extlookup/src/dspam.c 2008-04-20 14:41:22.000000000 +0100
@@ -84,6 +84,11 @@
 #   endif
 #endif
 
+#ifdef EXT_LOOKUP
+#include "external_lookup.h"
+int verified_user = 0;
+#endif
+
 #include "dspam.h"
 #include "agent_shared.h"
 #include "pref.h"
@@ -99,6 +104,7 @@
 #define USE_SMTP        (_ds_read_attribute(agent_config, "DeliveryProto") && 
!strcmp(_ds_read_attribute(agent_config, "DeliveryProto"), "SMTP"))
 #define LOOKUP(A, B)   ((_ds_pref_val(A, "localStore")[0]) ? _ds_pref_val(A, 
"localStore") : B)
 
+                                                                               
                                                                                
                          
 int
 main (int argc, char *argv[])
 {
@@ -129,6 +135,7 @@
     goto BAIL;
   }
 
+  
   /* Read dspam.conf into global config structure (ds_config_t) */
 
   agent_config = read_config(NULL);
@@ -1588,7 +1595,30 @@
      * or the current user if not present. 
      */
 
-    username = node_nt->ptr;
+
+#ifdef EXT_LOOKUP
+       verified_user = 0;
+       if (_ds_match_attribute(agent_config, "ExtLookup", "on")) {
+               LOGDEBUG ("looking up user %s using %s driver.", node_nt->ptr, 
_ds_read_attribute(agent_config, "ExtLookupDriver"));
+               username = external_lookup(agent_config, node_nt->ptr, 
username);
+               if (username != NULL) {
+                       LOGDEBUG ("external lookup verified user %s", 
node_nt->ptr);
+                       verified_user = 1;
+                       if (_ds_match_attribute(agent_config, "ExtLookupMode", 
"map") ||
+                                       _ds_match_attribute(agent_config, 
"ExtLookupMode", "strict")) {
+                                               LOGDEBUG ("mapping address %s 
to uid %s", node_nt->ptr, username);
+                                               node_nt->ptr = username;
+                       }
+               } else if (_ds_match_attribute(agent_config, "ExtLookupMode", 
"map")) {
+                               LOGDEBUG ("no match for user %s but mode is %s. 
continuing...", node_nt->ptr, _ds_read_attribute(agent_config, 
"ExtLookupMode"));
+                               verified_user = 1;
+               }
+       } else {
+               verified_user = 1;
+       }
+#endif
+       username = node_nt->ptr;
+       
     presult = calloc(1, sizeof(struct agent_result));
     if (node_rcpt) { 
       ATX->recipient = node_rcpt->ptr;
diff -Nru dspam/src/dspam.conf.in dspam-extlookup/src/dspam.conf.in
--- dspam/src/dspam.conf.in     2008-03-10 04:52:22.000000000 +0000
+++ dspam-extlookup/src/dspam.conf.in   2008-04-20 14:41:22.000000000 +0100
@@ -461,18 +461,42 @@
 #
 HashConnectionCache    10
 
-# -- LDAP --
 
-#
-# LDAP: Perform various LDAP functions depending on LDAPMode variable.
-# Presently, the only mode supported is 'verify', which will verify the 
-# existence of an unknown user in LDAP prior to creating them as a new user in 
-# the system.  This is useful on some systems acting as gateway machines.
-#
-#LDAPMode      verify
-#LDAPHost      ldaphost.mydomain.com
-#LDAPFilter    "(mail=%u)"
-#LDAPBase      ou=people,dc=domain,dc=com
+# -- ExtLookup --
+
+# ExtLookup: Prefrom various external lookup functions depending on 
user-defined variables.
+# ExtLookup can either be set to 'on' or 'off'. The behavior of such lookups 
are defined by the
+# use of ExtLookupMode, which can be set to 'verify', 'map' and 'strict'.
+#              'verify' will cause dspam to validate the user, prior to 
creating the user entry in the
+#                      system.
+#              'map' will cause dspam to try to map the user address to a 
certain unique identifier.
+#              'strict' will cause dspam to enforce both 'verify' and 'map'.
+# ExtLookupDriver will set the engine behind the lookups. For now the only 
supported mechanisms are
+# 'ldap' and 'program'. The first will make dspam talk directly to the 
configured LDAP server. The
+# second will prefrom the various lookup functions by running a certain binary 
program or executable
+# script. The program MUST be a binary executable or a script with a well 
defined interperter in its
+# first line ( #!/path/to/interperter ). There are plans to support TLS/SSL 
connections to backend
+# databases.
+#
+#ExtLookup                     on                                              
                # Turns on/off external lookup
+#ExtLookupMode         strict                                                  
# available modes are 'verify', 'map' and 'strict'.
+# 'strict' enforces both verify and map
+#ExtLookupDriver       ldap                                                    
# Currently only ldap and program are supported.
+# There are plans to support both MySQL and Postgres.
+#ExtLookupServer       ldap.domain.com                                 # Can 
either be a database hostname or the full path to
+# an executable lookup program and its arguments.
+#ExtLookupPort         389                                                     
        # Desired port when connecting to the lookup database.
+#ExtLookupDB           "ou=Users,dc=domain,dc=com"             # Can either be 
an LDAP search base or a database name (TODO).
+#ExtLookupQuery                
"(&(objectClass=qmailUser)(|(mail=%u)(mailAlternateAddress=%u)))"
+# Can either be an LDAP search filter or an SQL query (TODO)
+#ExtLookupLDAPAttribute        "mail"                                          
# Attribute to be used when ExtLookupDriver is 'ldap'
+# and ExtLookupMode 'map' or 'strict'
+#ExtLookupLDAPScope            sub                                             
        # Can be set to 'base', 'sub' or 'one'. Only used when ExtLookupDriver 
is 'ldap'.
+#ExtLookupLDAPVersion  3                                                       
# Sets the LDAP protocol version (1, 2 or 3)
+#ExtLookupLogin                "cn=admin,dc=domain,dc=com"             # Login 
to be used when connecting to any direct database backend.
+#ExtLookupPassword     itsasecret                                              
# Password to use with ExtLookupLogin.
+#ExtLookupCrypto       tls                                                     
        # Sets the use of TLS on backend communication (only compatible with 
LDAPv3)
+
 
 # -- Profiles --
 
diff -Nru dspam/src/external_lookup.c dspam-extlookup/src/external_lookup.c
--- dspam/src/external_lookup.c 1970-01-01 01:00:00.000000000 +0100
+++ dspam-extlookup/src/external_lookup.c       2008-04-20 14:41:22.000000000 
+0100
@@ -0,0 +1,422 @@
+/*
+ COPYRIGHT (C) 2006 HUGO MONTEIRO
+
+ external lookup library for DSPAM v0.6
+ 
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; version 2
+ of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <auto-config.h>
+#endif
+
+#ifdef EXT_LOOKUP
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include "agent_shared.h"
+#include "libdspam.h"
+#include "external_lookup.h"
+#include "config.h"
+#include "language.h"
+#include "error.h"
+#include "config_shared.h"
+
+
+/* LDAP */
+#include <ldap.h>
+#define BIND_TIMEOUT   10
+
+
+void 
+sig_alrm(int signum)
+{
+   LOG(LOG_ERR,"%s: Timed out.", ERR_EXT_LOOKUP_INIT_FAIL);
+   exit(200);
+}
+
+
+char*
+external_lookup(config_t agent_config, const char *username, char 
*external_uid)
+{
+
+       char *driver = _ds_read_attribute(agent_config, "ExtLookupDriver");
+
+       if (strcmp(driver, "ldap") == 0)
+               return ldap_lookup(agent_config, username, external_uid);
+       else if (strcmp(driver, "program") == 0)
+               return program_lookup(agent_config, username, external_uid);
+       /* add here your 'else if' statements like the one above to extend */
+       else if (driver == NULL) {
+               LOG(LOG_ERR, "external_lookup: lookup driver not defined");
+               return NULL;
+       } else {
+               LOG(LOG_ERR, "external_lookup: lookup driver %s not yet 
implemented.", driver);
+               return NULL;
+       }
+}
+
+
+char
+*transcode_query(const char *query, const char *username, char 
*transcoded_query)
+{      
+       
+       char *saveptr, *token;
+       int i, j, len, replacements;
+       int namelen = strlen(username);
+       int querylen = strlen(query);
+       char *str = malloc (querylen);
+
+       /* count aprox. the number of replacements.
+        * %% escaping is also accounted and shouldn't
+        * in the TODO */
+       for (replacements = 0, str=strdup(query); ; str = NULL) {
+               token = strtok_r(str, "%", &saveptr);
+               if (token == NULL)
+                       break;
+               if (token[0] == 'u') {
+                       replacements++;
+               }
+       }
+
+       free(str);
+       
+       len = querylen + namelen * replacements - 2 * replacements + 1;
+
+       transcoded_query = malloc (len);
+       memset(transcoded_query, 0, len);
+
+    for (i=j=0;j<len && query[i]; ){
+               if (query[i] == '%') {
+                   switch (query[i+1]) {
+                               case '%': /* escaped '%' character */
+                                   transcoded_query[j++] = '%';
+                                   break;
+                               case 'u': /* paste in the username */
+                                   if (j+namelen>=len) {
+                                               LOG(LOG_ERR, "%s: check 
ExtLookupQuery", ERR_EXT_LOOKUP_MISCONFIGURED);
+                                               return NULL;
+                                   }
+                                   memcpy (transcoded_query+j, username, 
namelen);
+                                   j += namelen;
+                                   break;
+                               default: /* unrecognised formatting, abort!  */
+                                       LOG(LOG_ERR, "%s: check 
ExtLookupQuery", ERR_EXT_LOOKUP_MISCONFIGURED);
+                               return NULL;
+                   }
+                   i += 2;
+               } else {
+                   transcoded_query[j++] = query[i++];
+               }
+       }
+
+    if (j>=len) {
+               LOG(LOG_ERR, "%s: check ExtLookupQuery", 
ERR_EXT_LOOKUP_MISCONFIGURED);
+               return NULL;
+    }
+    /* and finally zero terminate string */
+    transcoded_query[j] = 0;
+       
+       return transcoded_query;
+}
+
+
+char*
+ldap_lookup(config_t agent_config, const char *username, char *external_uid)
+{
+       LDAP            *ld;
+       LDAPMessage     *result = (LDAPMessage *) 0;
+       LDAPMessage     *e;
+       BerElement      *ber;
+       char            *a, *dn;
+       char            **vals = NULL;
+       struct          timeval ldaptimeout = {0};
+       int                     i, rc=0, num_entries=0;
+       char            *transcoded_query;
+       char            *ldap_uri;
+       char            *end_ptr;
+       char            *ldap_host = _ds_read_attribute(agent_config, 
"ExtLookupServer");
+       char            *port = _ds_read_attribute(agent_config, 
"ExtLookupPort");
+       long            lldap_port;
+       int                     ldap_port = 389;
+       char            *ldap_binddn = _ds_read_attribute(agent_config, 
"ExtLookupLogin");
+       char            *ldap_passwd = _ds_read_attribute(agent_config, 
"ExtLookupPassword");
+       char            *ldap_base = _ds_read_attribute(agent_config, 
"ExtLookupDB");
+       char            *ldap_attrs[] = {_ds_read_attribute(agent_config, 
"ExtLookupLDAPAttribute"),0};
+       char            *version = _ds_read_attribute(agent_config, 
"ExtLookupLDAPVersion");
+       long            lldap_version;
+       int                     ldap_version = 3;
+       char            *ldap_filter = _ds_read_attribute(agent_config, 
"ExtLookupQuery");
+       int                     ldap_scope;
+
+       if (port != NULL) {
+               errno=0;
+               lldap_port = strtol(port, &end_ptr, 0);
+               if ( (errno != 0) || (lldap_port < INT_MIN) || (lldap_port > 
INT_MAX) || (*end_ptr != '\0')) {
+                       LOG(LOG_ERR, "External Lookup: bad LDAP port number");
+                       return NULL;
+               } else
+                       ldap_port = (int)lldap_port;
+       }
+
+       /* set ldap protocol version */
+       if (version != NULL) {
+               errno=0;
+               lldap_version = strtol(version, &end_ptr, 0);
+               if ((errno != 0) || (lldap_version < 1) || (lldap_version > 3) 
|| (*end_ptr != '\0')) {
+                       LOG(LOG_ERR, "External Lookup: bad LDAP protocol 
version");
+                       return NULL;
+               } else
+                       ldap_version = (int)lldap_version;
+       }
+               
+       if (_ds_match_attribute(agent_config, "ExtLookupLDAPScope", "one"))
+               ldap_scope = LDAP_SCOPE_ONELEVEL;
+       else /* defaults to sub */
+               ldap_scope = LDAP_SCOPE_SUBTREE;
+
+       /* set up the ldap search timeout */
+       ldaptimeout.tv_sec  = BIND_TIMEOUT;
+       ldaptimeout.tv_usec = 0;
+
+       /* set alarm handler */
+       signal(SIGALRM, sig_alrm);
+
+       /* build proper LDAP filter*/
+       transcoded_query = strdup(transcode_query(ldap_filter, username, 
transcoded_query));
+       if (transcoded_query == NULL) {
+               LOG(LOG_ERR, "External Lookup: %s", 
ERR_EXT_LOOKUP_MISCONFIGURED); 
+               return NULL;
+       }
+
+       if( ldap_host != NULL || ldap_port ) {
+       /* construct URL */
+               LDAPURLDesc url;
+               memset( &url, 0, sizeof(url));
+
+               url.lud_scheme = "ldap";
+               url.lud_host = ldap_host;
+               url.lud_port = ldap_port;
+               url.lud_scope = LDAP_SCOPE_SUBTREE;
+
+               ldap_uri = ldap_url_desc2str( &url );
+       }
+
+       rc = ldap_initialize( &ld, ldap_uri );
+       if( rc != LDAP_SUCCESS ) {
+               LOG(LOG_ERR, "External Lookup: Could not create LDAP session 
handle for URI=%s (%d): %s\n", ldap_uri, rc, ldap_err2string(rc));
+               return NULL;
+       }
+
+       if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &ldap_version ) != 
LDAP_OPT_SUCCESS ) {
+               LOG(LOG_ERR, "External Lookup: Could not set 
LDAP_OPT_PROTOCOL_VERSION %d\n", ldap_version );
+               return NULL;
+       }
+
+       /* use TLS if configured */
+       if ( _ds_match_attribute(agent_config, "ExtLookupCrypto", "tls" )) {
+               if (ldap_version != 3) {
+                       LOG(LOG_ERR, "External Lookup: TLS only supported with 
LDAP protocol version 3");
+                       return NULL;
+               }
+               if ( ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
+                       LOG(LOG_ERR, "External Lookup: %s: %s (%d)", 
ERR_EXT_LOOKUP_INIT_FAIL, strerror(errno), errno);
+                       return NULL;
+               }
+       }
+
+       /* schedules alarm */
+       alarm(BIND_TIMEOUT);
+       
+       /* authenticate to the directory */
+       if ( (rc = ldap_simple_bind_s( ld, ldap_binddn, ldap_passwd )) != 
LDAP_SUCCESS ) {
+               /* cancel alarms */
+               alarm(0);
+               
+               LOG(LOG_ERR, "External Lookup: %s: %s", 
ERR_EXT_LOOKUP_INIT_FAIL, ldap_err2string(rc) );
+               ldap_unbind(ld);
+               return NULL;
+       }
+       /* cancel alarms */
+       alarm(0);
+       
+       /* search for all entries matching the filter */
+
+       if ( (rc = ldap_search_st( ld, 
+                                  ldap_base, 
+                                  ldap_scope,
+                                  transcoded_query,
+                                  ldap_attrs, 
+                                  0,
+                                  &ldaptimeout, 
+                                  &result )) != LDAP_SUCCESS ) {
+
+       free(transcoded_query);
+
+       switch(rc) {
+               case LDAP_TIMEOUT:
+               case LDAP_BUSY:
+               case LDAP_UNAVAILABLE:
+               case LDAP_UNWILLING_TO_PERFORM:
+               case LDAP_SERVER_DOWN:
+               case LDAP_TIMELIMIT_EXCEEDED:
+                       LOG(LOG_ERR, "External Lookup: %s: %s", 
ERR_EXT_LOOKUP_SEARCH_FAIL, ldap_err2string(ldap_result2error(ld, result, 1)) );
+                       ldap_unbind( ld );
+                       return NULL;
+                       break;
+               case LDAP_FILTER_ERROR:
+                       LOG(LOG_ERR, "External Lookup: %s: %s", 
ERR_EXT_LOOKUP_SEARCH_FAIL, ldap_err2string(ldap_result2error(ld, result, 1)) );
+                       ldap_unbind( ld );
+                       return NULL;
+                       break;
+               case LDAP_SIZELIMIT_EXCEEDED:
+                       if ( result == NULL ) {
+                               LOG(LOG_ERR, "External Lookup: %s: %s", 
ERR_EXT_LOOKUP_SEARCH_FAIL, ldap_err2string(ldap_result2error(ld, result, 1)) );
+                               ldap_unbind( ld );
+                               return NULL;
+                       }
+                       break;
+               default:                       
+                       LOG(LOG_ERR, "External Lookup: %s: code=%d, %s", 
ERR_EXT_LOOKUP_SEARCH_FAIL, rc, ldap_err2string(ldap_result2error(ld, result, 
1)) );
+                       ldap_unbind( ld );
+                       return NULL;
+               }
+       }
+
+       num_entries=ldap_count_entries(ld,result);
+
+       LOGDEBUG("External Lookup: found %d LDAP entries", num_entries);
+
+    switch (num_entries) {
+                               case 1: /* only one entry, let's proceed */
+                                       break;
+                                       
+                               case -1: /* an error occured */
+                                   LOG(LOG_ERR, "External Lookup: %s: %s", 
ERR_EXT_LOOKUP_SEARCH_FAIL, ldap_err2string(ldap_result2error(ld, result, 1)));
+                                       ldap_unbind( ld );
+                                       return NULL ;
+                                       
+                               case 0: /* no entries found */
+                                       LOGDEBUG("External Lookup: %s: no 
entries found.", ERR_EXT_LOOKUP_SEARCH_FAIL);
+                                       ldap_msgfree( result );
+                                       ldap_unbind( ld );
+                                       return NULL ;
+
+                               default: /* more than one entry returned */
+                                       LOG(LOG_ERR, "External Lookup: %s: more 
than one entry returned.", ERR_EXT_LOOKUP_SEARCH_FAIL);
+                                       ldap_msgfree( result );
+                                       ldap_unbind( ld );
+                               return NULL;
+       }
+
+       /* for each entry print out name + all attrs and values */
+       for ( e = ldap_first_entry( ld, result ); e != NULL;
+           e = ldap_next_entry( ld, e ) ) {
+               if ( (dn = ldap_get_dn( ld, e )) != NULL ) {
+                   ldap_memfree( dn );
+               }
+               for ( a = ldap_first_attribute( ld, e, &ber );
+                   a != NULL; a = ldap_next_attribute( ld, e, ber ) ) {
+                       if ((vals = ldap_get_values( ld, e, a)) != NULL ) {
+                               for ( i = 0; vals[i] != NULL; i++ ) {
+                                       external_uid = strdup(vals[i]);
+                               }
+                               ldap_value_free( vals );
+                       }
+                       ldap_memfree( a );
+               }
+               if ( ber != NULL ) {
+                       ber_free( ber, 0 );
+               }
+       }
+       ldap_msgfree( result );
+       ldap_unbind( ld );
+       return external_uid;
+}
+
+
+
+char*
+program_lookup(config_t agent_config, const char *username, char *external_uid)
+{
+       int pid, i;
+       int fd[2];
+       char *output = malloc (1024);
+       char **args = malloc (1024);
+       char *token;
+       char *saveptr;
+       char *str;
+       char *command_line = 0;
+       
+    /* build proper command line*/
+       command_line = strdup(transcode_query(_ds_read_attribute(agent_config, 
"ExtLookupServer"), username, command_line));
+
+       if (command_line == NULL) {
+               LOG(LOG_ERR, ERR_EXT_LOOKUP_MISCONFIGURED); 
+               return NULL;
+       }
+
+       LOGDEBUG("command line is %s", command_line);
+       
+       /* break the command line into arguments */
+       for (i = 0, str = command_line; ; i++, str = NULL) {
+               token = strtok_r(str, " ", &saveptr);
+               if (token == NULL)
+                       break;
+               args[i] = token;
+       }
+       args[i] = (char *) 0;
+
+       pipe(fd);
+       pid = fork();
+
+       if (pid == 0) { /* execute the command and write to fd */
+               close(fd[0]);
+               dup2(fd[1], fileno(stdout));
+               if (execve(args[0], args, 0) == -1) {
+                       LOG(LOG_ERR, "%s: errno=%i (%s)", 
ERR_EXT_LOOKUP_INIT_FAIL, errno, strerror(errno));
+                       return NULL;
+               }
+       } else { /* read from fd the first output line */
+               close(fd[1]);
+               /* just in case there's no line break at the end of the 
return... */
+               memset(output, 0, 1024);
+               read(fd[0], output, 1024);
+       }
+
+       if (strlen(output) == 0)
+               return NULL;
+       
+       /* terminate the output string at the first \n */
+       token = strchr(output, '\n');
+       if (token != NULL)
+               *token = '\0';
+       
+       external_uid = strdup(output);
+       free(output);
+       free(command_line);
+       free(args);
+       return external_uid;
+}
+#endif
diff -Nru dspam/src/external_lookup.h dspam-extlookup/src/external_lookup.h
--- dspam/src/external_lookup.h 1970-01-01 01:00:00.000000000 +0100
+++ dspam-extlookup/src/external_lookup.h       2008-04-20 14:41:22.000000000 
+0100
@@ -0,0 +1,40 @@
+/*
+ COPYRIGHT (C) 2006 HUGO MONTEIRO
+
+ external lookup library for DSPAM v0.1
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; version 2
+ of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#ifdef EXT_LOOKUP
+
+#ifndef _EXT_LOOKUP_H
+#define _EXT_LOOKUP_H
+
+#include "agent_shared.h"
+#include "libdspam.h"
+
+int verified_user;
+
+void sig_alrm(int signum);
+char *transcode_query(const char *query, const char *username, char 
*transcoded_query);
+char *external_lookup(config_t agent_config, const char *username, char 
*external_uid);
+char *ldap_lookup(config_t agent_config, const char *username, char 
*external_uid);
+char *program_lookup(config_t agent_config, const char *username, char 
*external_uid);
+
+#endif /* _EXTERNAL_LOOKUP_H */
+
+#endif /* USE_EXTLOOKUP */
diff -Nru dspam/src/language.h dspam-extlookup/src/language.h
--- dspam/src/language.h        2008-03-10 04:47:09.000000000 +0000
+++ dspam-extlookup/src/language.h      2008-04-20 14:41:22.000000000 +0100
@@ -37,12 +37,12 @@
 #define ERR_IO_LOCK             "Failed to lock file %s: %d: %s"
 #define ERR_IO_LOCK_FREE       "Failed to free lock file %s: %d: %s"
 
-/* LDAP related error codes */
+/* External lookup related error codes */
 
-#define ERR_LDAP_INIT_FAIL     "LDAP initialization failed"
-#define ERR_LDAP_PROTO_VER_FAIL        "LDAP failure: unable to set protocol 
version"
-#define ERR_LDAP_SEARCH_FAIL   "LDAP search failure"
-#define ERR_LDAP_MISCONFIGURED "LDAP misconfigured"
+#define ERR_EXT_LOOKUP_INIT_FAIL       "Backend initialization failure"
+#define ERR_EXT_LOOKUP_LDAP_PROTO_VER_FAIL     "Unable to set LDAP protocol 
version"
+#define ERR_EXT_LOOKUP_SEARCH_FAIL     "Backend search failure"
+#define ERR_EXT_LOOKUP_MISCONFIGURED   "External Lookup misconfigured"
 
 /* Agent error codes */
 
diff -Nru dspam/src/ldap_client.c dspam-extlookup/src/ldap_client.c
--- dspam/src/ldap_client.c     2007-12-07 00:11:51.000000000 +0000
+++ dspam-extlookup/src/ldap_client.c   1970-01-01 01:00:00.000000000 +0100
@@ -1,91 +0,0 @@
-/* $Id: ldap_client.c,v 1.6 2007/12/07 00:11:51 mjohnson Exp $ */
-
-/*
- DSPAM
- COPYRIGHT (C) 2002-2006 JONATHAN A. ZDZIARSKI
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; version 2
- of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <auto-config.h>
-#endif
-
-#ifdef USE_LDAP
-
-#define LDAP_DEPRECATED 1
-#include <ldap.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "libdspam.h"
-#include "ldap_client.h"
-#include "config.h"
-#include "language.h"
-#include "error.h"
-#include "config_shared.h"
-
-int ldap_verify(DSPAM_CTX *CTX, const char *username) {
-  LDAP *ld;
-  int result, i;
-  int desired_version = LDAP_VERSION3;
-  char *ldap_host     = _ds_read_attribute(CTX->config->attributes, 
"LDAPHost");
-  char search_filter[1024];
-  LDAPMessage *msg;
-
-  char* base = _ds_read_attribute(CTX->config->attributes, "LDAPBase");
-  char* filter = _ds_read_attribute(CTX->config->attributes, "LDAPFilter");
-
-  if (!base || !filter || !ldap_host) {
-    LOG(LOG_ERR, ERR_LDAP_MISCONFIGURED); 
-    return EFAILURE;
-  }
-
-  for(i=0;i<strlen(filter);i++) {
-    if (filter[i] == '%' && filter[i+1] == 'u') {
-      filter[i+1] = 's';
-    }
-  }
-
-  snprintf(search_filter, sizeof(search_filter), filter, username);
-
-  if ((ld = ldap_init(ldap_host, LDAP_PORT)) == NULL ) {
-    LOG(LOG_ERR, ERR_LDAP_INIT_FAIL);
-    return EFAILURE;
-  }
-
-  if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &desired_version) 
-    != LDAP_OPT_SUCCESS)
-  {
-    LOG(LOG_ERR, ERR_LDAP_PROTO_VER_FAIL);
-    return EFAILURE;
-  }
-
-  if (ldap_search_s(ld, base, LDAP_SCOPE_SUBTREE, search_filter, NULL, 0, &msg)
-   != LDAP_SUCCESS) 
-  {
-    LOG(LOG_ERR, ERR_LDAP_SEARCH_FAIL);
-    return EFAILURE;
-  }
-
-  result = ldap_count_entries(ld, msg) > 0;
-  ldap_msgfree (msg);
-  ldap_unbind(ld);
-  return result;
-}
-
-#endif
-
diff -Nru dspam/src/ldap_client.h dspam-extlookup/src/ldap_client.h
--- dspam/src/ldap_client.h     2006-05-13 02:12:59.000000000 +0100
+++ dspam-extlookup/src/ldap_client.h   1970-01-01 01:00:00.000000000 +0100
@@ -1,38 +0,0 @@
-/* $Id: ldap_client.h,v 1.4 2006/05/13 01:12:59 jonz Exp $ */
-
-/*
- DSPAM
- COPYRIGHT (C) 2002-2006 JONATHAN A. ZDZIARSKI
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; version 2
- of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <auto-config.h>
-#endif
-
-#ifdef USE_LDAP
-
-#ifndef _LDAP_CLIENT_H
-#define _LDAP_CLIENT_H
-
-#include "libdspam.h"
-
-int ldap_verify(DSPAM_CTX *CTX, const char *username);
-
-#endif /* _LDAP_CLIENT_H */
-
-#endif /* USE_LDAP */
diff -Nru dspam/src/Makefile.am dspam-extlookup/src/Makefile.am
--- dspam/src/Makefile.am       2007-12-07 00:11:51.000000000 +0000
+++ dspam-extlookup/src/Makefile.am     2008-04-20 14:41:47.000000000 +0100
@@ -60,7 +60,7 @@
 
 # installed for libdspam
 include_HEADERS = buffer.h config_shared.h decode.h error.h diction.h \
-       libdspam.h libdspam_objects.h nodetree.h tokenizer.h ldap_client.h \
+       libdspam.h libdspam_objects.h nodetree.h tokenizer.h external_lookup.h \
        storage_driver.h heap.h config.h pref.h read_config.h
 
 # libdspam.a contans objects common for dspam and tools/* binaries
@@ -81,7 +81,7 @@
        bnr.c bnr.h \
        hash.c hash.h \
        list.c list.h \
-       ldap_client.c ldap_client.h \
+       external_lookup.c external_lookup.h \
        tokenizer.c tokenizer.h \
        storage_driver.h
 
diff -Nru dspam/src/mysql_drv.c dspam-extlookup/src/mysql_drv.c
--- dspam/src/mysql_drv.c       2007-12-07 00:11:52.000000000 +0000
+++ dspam-extlookup/src/mysql_drv.c     2008-04-20 14:42:11.000000000 +0100
@@ -51,9 +51,6 @@
 #   endif
 #endif
 
-#ifdef USE_LDAP
-#include "ldap_client.h"
-#endif
 
 #include "storage_driver.h"
 #include "mysql_drv.h"
@@ -1836,11 +1833,10 @@
     "MySQLVirtualUsernameField")) ==NULL)
   { virtual_username = "username"; }
 
-#ifdef USE_LDAP
-  if (_ds_match_attribute(CTX->config->attributes, "LDAPMode", "verify") &&
-      ldap_verify(CTX, name)<=0) 
-  {
-    LOGDEBUG("LDAP verification of %s failed: not adding user", name);
+#ifdef EXT_LOOKUP
+  LOGDEBUG("verified_user is %d", verified_user);
+  if (verified_user == 0) {
+    LOGDEBUG("External lookup verification of %s failed: not adding user", 
name);
     return NULL;
   }
 #endif
diff -Nru dspam/src/mysql_drv.h dspam-extlookup/src/mysql_drv.h
--- dspam/src/mysql_drv.h       2006-05-13 02:12:59.000000000 +0100
+++ dspam-extlookup/src/mysql_drv.h     2008-04-20 14:42:11.000000000 +0100
@@ -75,6 +75,10 @@
 struct passwd *_mysql_drv_setpwnam     (DSPAM_CTX * CTX, const char *name);
 #endif
 
+#ifdef EXT_LOOKUP
+int verified_user;
+#endif
+
 #ifdef PREFERENCES_EXTENSION
 int _mysql_drv_set_attributes(DSPAM_CTX *CTX, config_t config);
 #endif
diff -Nru dspam/src/pgsql_drv.c dspam-extlookup/src/pgsql_drv.c
--- dspam/src/pgsql_drv.c       2008-02-02 21:30:17.000000000 +0000
+++ dspam-extlookup/src/pgsql_drv.c     2008-04-20 14:42:11.000000000 +0100
@@ -51,10 +51,6 @@
 #   endif
 #endif
 
-#ifdef USE_LDAP
-#include "ldap_client.h"
-#endif
-
 #include "storage_driver.h"
 #include "pgsql_drv.h"
 #include "libdspam.h"
@@ -1941,15 +1937,14 @@
     "PgSQLVirtualUsernameField")) ==NULL)
   { virtual_username = "username"; }
 
-#ifdef USE_LDAP
-  if (_ds_match_attribute(CTX->config->attributes, "LDAPMode", "verify") &&
-      ldap_verify(CTX, name)<=0)
-  {
-    LOGDEBUG("LDAP verification of %s failed: not adding user", name);
+#ifdef EXT_LOOKUP
+  LOGDEBUG("verified_user is %d", verified_user);
+  if (verified_user == 0) {
+    LOGDEBUG("External lookup verification of %s failed: not adding user", 
name);
     return NULL;
   }
 #endif
-
+  
   snprintf (query, sizeof (query),
             "INSERT INTO %s (%s, %s) VALUES (default, '%s')",
             virtual_table, virtual_uid, virtual_username, name);
diff -Nru dspam/src/pgsql_drv.h dspam-extlookup/src/pgsql_drv.h
--- dspam/src/pgsql_drv.h       2006-05-13 02:12:59.000000000 +0100
+++ dspam-extlookup/src/pgsql_drv.h     2008-04-20 14:42:11.000000000 +0100
@@ -75,6 +75,10 @@
 struct passwd *_pgsql_drv_setpwnam     (DSPAM_CTX * CTX, const char *name);
 #endif
 
+#ifdef EXT_LOOKUP
+int verified_user;
+#endif
+
 #ifdef PREFERENCES_EXTENSION
 int _pgsql_drv_set_attributes(DSPAM_CTX *CTX, config_t config);
 #endif
diff -Nru dspam/src/util.c dspam-extlookup/src/util.c
--- dspam/src/util.c    2007-12-14 00:14:32.000000000 +0000
+++ dspam-extlookup/src/util.c  2008-04-20 14:42:11.000000000 +0100
@@ -429,8 +429,13 @@
     /* don't try to create root directory of a drive */
     if ( path[2] != '\0' || path[1] != ':' )
 #endif
-    {
-      if (dir != NULL && stat (path, &s) && path[0] != 0)
+   {
+#ifdef EXT_LOOKUP
+         /* don't create users data dir if user verification is required */
+      if (dir != NULL && stat (path, &s) && path[0] != 0 && verified_user == 1)
+#else
+         if (dir != NULL && stat (path, &s) && path[0] != 0)
+#endif
       {
         int x;
         LOGDEBUG ("creating directory '%s'", path);
diff -Nru dspam/src/util.h dspam-extlookup/src/util.h
--- dspam/src/util.h    2006-05-13 02:12:59.000000000 +0100
+++ dspam-extlookup/src/util.h  2008-04-20 14:42:11.000000000 +0100
@@ -90,6 +90,10 @@
   (struct in_addr in, char *buf, int len);
 #endif
 
+#ifdef EXT_LOOKUP
+  int verified_user;
+#endif
+
 const char *   _ds_userdir_path (
   char *buff,
   const char *home,

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to