Mailing List Archive

svn commit: rev 6536 - in incubator/spamassassin/trunk: . ldap lib/Mail lib/Mail/SpamAssassin spamd t
Author: jm
Date: Thu Feb 5 22:49:55 2004
New Revision: 6536

Added:
incubator/spamassassin/trunk/ldap/
incubator/spamassassin/trunk/ldap/README
incubator/spamassassin/trunk/ldap/README.testing
incubator/spamassassin/trunk/ldap/sa_test.ldif
incubator/spamassassin/trunk/t/spamd_ldap.t (contents, props changed)
Modified:
incubator/spamassassin/trunk/CREDITS
incubator/spamassassin/trunk/MANIFEST
incubator/spamassassin/trunk/lib/Mail/SpamAssassin.pm
incubator/spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm
incubator/spamassassin/trunk/spamd/README
incubator/spamassassin/trunk/spamd/spamd.raw
Log:
bug 2205: LDAP support, from Kristian Koehntopp <kk(at)netuse.de>. spamd can now read configs from LDAP

Modified: incubator/spamassassin/trunk/CREDITS
==============================================================================
--- incubator/spamassassin/trunk/CREDITS (original)
+++ incubator/spamassassin/trunk/CREDITS Thu Feb 5 22:49:55 2004
@@ -52,6 +52,8 @@
to avoid losing mail from spamc; BSMTP and -e support; tracking of
number of spamd processes; several other mods.

+ - Kristian Koehntopp <kk(at)netuse.de>: LDAP support.
+
- Sidney Markowitz, <sidney(at)sidney.com>: fix to DNS tests;
message-size sanity-checking in spamc; language identification;
Win32 build support.

Modified: incubator/spamassassin/trunk/MANIFEST
==============================================================================
--- incubator/spamassassin/trunk/MANIFEST (original)
+++ incubator/spamassassin/trunk/MANIFEST Thu Feb 5 22:49:55 2004
@@ -33,6 +33,7 @@
lib/Mail/SpamAssassin/CmdLearn.pm
lib/Mail/SpamAssassin/Conf.pm
lib/Mail/SpamAssassin/ConfSourceSQL.pm
+lib/Mail/SpamAssassin/ConfSourceLDAP.pm
lib/Mail/SpamAssassin/DBBasedAddrList.pm
lib/Mail/SpamAssassin/Dns.pm
lib/Mail/SpamAssassin/EvalTests.pm
@@ -288,3 +289,7 @@
t/data/whitelists/sf.net
t/data/whitelists/winxpnews.com
t/data/whitelists/yahoo-inc.com
+ldap/README
+ldap/sa_test.ldif
+ldap/README.testing
+t/spamd_ldap.t

Added: incubator/spamassassin/trunk/ldap/README
==============================================================================
--- (empty file)
+++ incubator/spamassassin/trunk/ldap/README Thu Feb 5 22:49:55 2004
@@ -0,0 +1,107 @@
+
+Using SpamAssassin With An LDAP Server
+--------------------------------------
+
+SpamAssassin can now load users' score files from an LDAP server. The concept
+here is to have a web application (PHP/perl/ASP/etc.) that will allow users to
+be able to update their local preferences on how SpamAssassin will filter their
+e-mail. The most common use for a system like this would be for users to be
+able to update the white list of addresses (whitelist_from) without the need
+for them to update their $HOME/.spamassassin/user_prefs file. It is also quite
+common for users listed in /etc/passwd to not have a home directory,
+therefore, the only way to have their own local settings would be through a
+database or LDAP server.
+
+SpamAssassin will check the global configuration file (ie. any file matching
+/etc/mail/spamassassin/*.cf) for the following settings:
+
+user_scores_dsn ldap://host:port/dc=basedn,dc=de?scope?attr?uid=__USERNAME__
+user_scores_ldap_username bind dn
+user_scores_ldap_password password
+
+The first option, user_scores_dsn, describes the data source name that will be
+used to create the connection to your LDAP server. You have to write the DSN as
+an LDAP URL, the components being the host and port to connect to, the base DN
+for the search, the scope of the search (base, one or sub), the single
+attribute being the multivalued attribute used to hold the configuration data
+(space separated pairs of key and value, just as in a file) and finally the
+filter being the expression used to filter out the wanted username. Note that
+the filter expression uses the literal text __USERNAME__ as a placeholder for
+the username (SpamAssassin will use a s///g statement to replace it with the
+actual username).
+
+Examples:
+
+ ldap://localhost:389/dc=koehntopp,dc=de?spamassassinconfig?sub?uid=__USERNAME__
+ ldap://localhost:389/o=stooges?spamassassin?sub?uid=__USERNAME__
+
+
+If the user_scores_dsn option does not exist, SpamAssassin will not attempt
+to use an LDAP server for retrieving users' preferences. Note that this will
+NOT look for test rules, only local scores, whitelist_from(s), required_hits,
+and auto_report_threshold.
+
+Requirements
+------------
+
+In order for SpamAssassin to work with your SQL database, you must have
+the perl Net::LDAP module installed. You'll also need the URI module.
+
+
+Database Schema
+---------------
+
+You can use any schema extension to your user entries with SpamAssassin,
+as long as the attribute is multivalued and correctly named in your LDAP url.
+We are currently using a <customername>spamassassin field that is part of
+our inetOrgPerson subclass.
+
+Here's an example for openldap's /etc/openldap/schema/inetorgperson.schema :
+
+ # spamassassin
+ # see http://SpamAssassin.org/ .
+ attributetype ( 2.16.840.1.113730.3.1.217
+ NAME 'spamassassin'
+ DESC 'SpamAssassin user preferences settings'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+(don't forget to add "$ spamassassin" to the objectclass MAY clause.)
+
+
+Testing SpamAssassin/LDAP
+-------------------------
+
+To test your LDAP setup, and debug any possible problems, you should start
+spamd with the -D option, which will keep spamd in the foreground, and will
+output debug message to the terminal. You should then test spamd with a
+message by calling spamc. You can use the sample-spam.txt file with the
+following command:
+
+ cat sample-spam.txt | spamc
+
+Watch the debug output from spamd and look for the following debug line:
+
+ retrieving LDAP prefs for <username>: <value>
+
+If you do not see the above text, then the LDAP query was not successful, and
+you should see any error messages reported. <username> should be the user
+that was passed to spamd and is usually the user executing spamc.
+
+If you need to set up LDAP, a good guide is here:
+http://yolinux.com/TUTORIALS/LinuxTutorialLDAP.html
+
+To test LDAP support using the SpamAssassin test suite, you need to
+perform a little bit of manual configuration first. See the file
+"ldap/README.testing" for details.
+
+
+******
+NB: This should be considered BETA, and the interface or overall
+operation of LDAP support may change at any time with future releases of SA.
+******
+
+Please send any comments to kk /at/ netuse.de , or to
+http://bugzilla.SpamAssassin.org/ .
+
+Kristian Köhntopp

Added: incubator/spamassassin/trunk/ldap/README.testing
==============================================================================
--- (empty file)
+++ incubator/spamassassin/trunk/ldap/README.testing Thu Feb 5 22:49:55 2004
@@ -0,0 +1,55 @@
+
+- install openldap server, using apt-get etc.
+
+- Patch '/etc/openldap/schema/inetorgperson.schema' as follows:
+
+--- /etc/openldap/schema/inetorgperson.schema.default 2003-10-23 07:26:01.000000000 -0700
++++ /etc/openldap/schema/inetorgperson.schema 2004-02-05 22:07:01.000000000 -0800
+@@ -121,6 +121,13 @@
+ DESC 'RFC2798: personal identity information, a PKCS #12 PFX'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 )
+
++# spamassassin
++# see http://SpamAssassin.org/ .
++attributetype ( 2.16.840.1.113730.3.1.220
++ NAME 'spamassassin'
++ DESC 'SpamAssassin user preferences settings'
++ EQUALITY caseExactMatch
++ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+ # inetOrgPerson
+ # The inetOrgPerson represents people who are associated with an
+@@ -138,5 +145,5 @@
+ labeledURI $ mail $ manager $ mobile $ o $ pager $
+ photo $ roomNumber $ secretary $ uid $ userCertificate $
+ x500uniqueIdentifier $ preferredLanguage $
+- userSMIMECertificate $ userPKCS12 )
++ userSMIMECertificate $ userPKCS12 $ spamassassin )
+ )
+
+
+- set up according to:
+
+ http://yolinux.com/TUTORIALS/LinuxTutorialLDAP.html#TUTORIAL
+
+ However, do not use "stooges.ldif"; use "sa_test.ldif" instead.
+ (This LDIF file adds a "spamassassin" line to the "curley" user.)
+
+ ldapadd -f sa_test.ldif -xv -D "cn=StoogeAdmin,o=stooges" \
+ -h 127.0.0.1 -w secret1
+
+
+- install Net::LDAP using CPAN:
+
+ perl -MCPAN -e shell
+ install Net::LDAP
+ quit
+
+
+- create the test flag file:
+
+ touch t/do_ldap
+
+
+- now "make test" will test against the LDAP server as well.
+

Added: incubator/spamassassin/trunk/ldap/sa_test.ldif
==============================================================================
--- (empty file)
+++ incubator/spamassassin/trunk/ldap/sa_test.ldif Thu Feb 5 22:49:55 2004
@@ -0,0 +1,99 @@
+dn: o=stooges
+objectClass: top
+objectClass: organization
+o: stooges
+description: The Three Stooges
+
+dn: cn=StoogeAdmin,o=stooges
+objectClass: organizationalRole
+cn: StoogeAdmin
+description: LDAP Directory Administrator
+
+dn: ou=MemberGroupA,o=stooges
+ou: MemberGroupA
+objectClass: top
+objectClass: organizationalUnit
+description: Members of MemberGroupA
+
+dn: ou=MemberGroupB,o=stooges
+ou: MemberGroupB
+objectClass: top
+objectClass: organizationalUnit
+description: Members of MemberGroupB
+
+dn: cn=Larry Anderson,ou=MemberGroupA,o=stooges
+ou: MemberGroupA
+o: stooges
+cn: Larry Anderson
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+mail: LAnderson@isp.com
+givenname: Larry
+sn: Anderson
+uid: larry
+homePostalAddress: 15 Cherry Ln.$Plano TX 78888
+postalAddress: 15 Fitzhugh Ave.
+l: Dallas
+st: TX
+postalcode: 76888
+telephoneNumber: (800)555-1212
+homePhone: 800-555-1313
+facsimileTelephoneNumber: 800-555-1414
+userPassword: larrysecret
+title: Account Executive
+
+dn: cn=Moe Anderson,ou=MemberGroupA,o=stooges
+ou: MemberGroupA
+o: stooges
+cn: Moe Anderson
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+mail: MAnderson@isp.com
+givenname: Moe
+sn: Anderson
+uid: moe
+initials: Bob
+homePostalAddress: 16 Cherry Ln.$Plano TX 78888
+postalAddress: 15 Fitzhugh Ave.
+l: Dallas
+st: TX
+postalcode: 76888
+pager: 800-555-1319
+homePhone: 800-555-1313
+telephoneNumber: (800)555-1213
+mobile: 800-555-1318
+title: Manager of Product Development
+facsimileTelephoneNumber: 800-555-3318
+manager: cn=Larry Anderson,ou=MemberGroupA,o=stooges
+userPassword: moesecret
+
+dn: cn=Curley Anderson,ou=MemberGroupB,o=stooges
+ou: MemberGroupB
+o: stooges
+cn: Curley Anderson
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+mail: CAnderson@isp.com
+givenname: Curley
+sn: Anderson
+uid: curley
+initials: Joe
+homePostalAddress: 14 Cherry Ln.$Plano TX 78888
+postalAddress: 15 Fitzhugh Ave.
+spamassassin: add_header all Foo LDAP read
+l: Dallas
+st: TX
+postalcode: 76888
+pager: 800-555-1319
+homePhone: 800-555-1313
+telephoneNumber: (800)555-1214
+mobile: 800-555-1318
+title: Developemnt Engineer
+facsimileTelephoneNumber: 800-555-3318
+userPassword: curleysecret

Modified: incubator/spamassassin/trunk/lib/Mail/SpamAssassin.pm
==============================================================================
--- incubator/spamassassin/trunk/lib/Mail/SpamAssassin.pm (original)
+++ incubator/spamassassin/trunk/lib/Mail/SpamAssassin.pm Thu Feb 5 22:49:55 2004
@@ -67,6 +67,7 @@

use Mail::SpamAssassin::Conf;
use Mail::SpamAssassin::ConfSourceSQL;
+use Mail::SpamAssassin::ConfSourceLDAP;
use Mail::SpamAssassin::PerMsgStatus;
use Mail::SpamAssassin::MsgParser;
use Mail::SpamAssassin::Bayes;
@@ -1033,6 +1034,29 @@
$src->load($username);
}

+###########################################################################
+
+=item $f->load_scoreonly_ldap ($username)
+
+Read configuration paramaters from an LDAP server and parse scores from it.
+This will only take effect if the perl C<Net::LDAP> and C<URI> modules are
+installed, and the configuration parameters C<user_scores_dsn>,
+C<user_scores_ldap_username>, and C<user_scores_ldap_password> are set
+correctly.
+
+The username in C<$username> will also be used for the C<username> attribute of
+the Mail::SpamAssassin object.
+
+=cut
+
+sub load_scoreonly_ldap {
+ my ($self, $username) = @_;
+
+ dbg("load_scoreonly_ldap($username)");
+ my $src = Mail::SpamAssassin::ConfSourceLDAP->new ($self);
+ $self->{username} = $username;
+ $src->load($username);
+}

###########################################################################

@@ -1092,7 +1116,11 @@
# load SQL modules now as well
my $dsn = $self->{conf}->{user_scores_dsn};
if ($dsn ne '') {
- Mail::SpamAssassin::ConfSourceSQL::load_modules();
+ if ($dsn =~ /^ldap:/i) {
+ Mail::SpamAssassin::ConfSourceLDAP::load_modules();
+ } else {
+ Mail::SpamAssassin::ConfSourceSQL::load_modules();
+ }
}

$self->{bayes_scanner}->sanity_check_is_untied();

Modified: incubator/spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm
==============================================================================
--- incubator/spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm (original)
+++ incubator/spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm Thu Feb 5 22:49:55 2004
@@ -275,6 +275,9 @@
# defaults for SQL based auto-whitelist
$self->{user_awl_sql_table} = 'awl';

+ $self->{user_scores_ldap_username} = 'username';
+ $self->{user_scores_ldap_password} = '';
+
# Make sure we add in X-Spam-Checker-Version
$self->{headers_spam}->{"Checker-Version"} = "SpamAssassin _VERSION_ (_SUBVERSION_) on _HOSTNAME_";
$self->{headers_ham}->{"Checker-Version"} = $self->{headers_spam}->{"Checker-Version"};
@@ -2473,6 +2476,18 @@
If you load user scores from an SQL database, this will set the DSN
used to connect. Example: C<DBI:mysql:spamassassin:localhost>

+If you load user scores from an LDAP directory, this will set the DSN used to
+connect. You have to write the DSN as an LDAP URL, the components being the
+host and port to connect to, the base DN for the seasrch, the scope of the
+search (base, one or sub), the single attribute being the multivalued attribute
+used to hold the configuration data (space separated pairs of key and value,
+just as in a file) and finally the filter being the expression used to filter
+out the wanted username. Note that the filter expression is being used in a
+sprintf statement with the username as the only parameter, thus is can hold a
+single __USERNAME__ expression. This will be replaced with the username.
+
+Example: C<ldap://localhost:389/dc=koehntopp,dc=de?spamassassinconfig?uid=__USERNAME__>
+
=cut

if ( $key eq 'user_scores_dsn' ) {
@@ -2539,6 +2554,28 @@
=cut
if ( $key eq 'user_awl_sql_table' ) {
$self->{user_awl_sql_table} = $value; next;
+ }
+
+=item user_scores_ldap_username
+
+This is the Bind DN used to connect to the LDAP server.
+
+Example: C<cn=master,dc=koehntopp,dc=de>
+
+=cut
+
+ if (/^user_scores_ldap_username\s+(.*?)\s*$/) {
+ $self->{user_scores_ldap_username} = $1; next;
+ }
+
+=item user_scores_ldap_password
+
+This is the password used to connect to the LDAP server.
+
+=cut
+
+ if (/^user_scores_ldap_password\s+(.*?)\s*$/) {
+ $self->{user_scores_ldap_password} = $1; next;
}

=item loadplugin PluginModuleName /path/to/module.pm

Modified: incubator/spamassassin/trunk/spamd/README
==============================================================================
--- incubator/spamassassin/trunk/spamd/README (original)
+++ incubator/spamassassin/trunk/spamd/README Thu Feb 5 22:49:55 2004
@@ -62,12 +62,11 @@
both the running uid of spamd, and the uid of the username supplied by spamc
(and this could be any user).

-When run as root, spamd will change uid's to the user invoking spamc in
-order to read and write to their configurations. This functionality
-is not possible if spamd does not run as root and is a disadvantage if
-you rely on this. If you use mysql for per-user configuration there
-is no reason in the world to run as root, and this remains fully
-functional.
+When run as root, spamd will change uid's to the user invoking spamc in order
+to read and write to their configurations. This functionality is not possible
+if spamd does not run as root and is a disadvantage if you rely on this. If you
+use mysql or LDAP for per-user configuration there is no reason in the world
+to run as root, and this remains fully functional.

If you do not need to let your users define their own rules, maintain
their own whitelists, or have non-world-readable home and ~/.spamassassin
@@ -118,8 +117,8 @@
If users do not have the opportunity to invoke spamc themselves, and
the network is secure, running spamd as root is the preferred option,
Be clear that the issues above dont affect you. Note: if you use mysql
-for per-user configuration on systems, you will remain vulnerable to
-(1.) and (2.).
+or LDAP for per-user configuration on systems, you will remain vulnerable
+to (1.) and (2.).

configuration: Mysql .spamassassin/user_prefs
/ \ / \

Modified: incubator/spamassassin/trunk/spamd/spamd.raw
==============================================================================
--- incubator/spamassassin/trunk/spamd/spamd.raw (original)
+++ incubator/spamassassin/trunk/spamd/spamd.raw Thu Feb 5 22:49:55 2004
@@ -123,8 +123,10 @@
'max-children|m=i' => \$opt{'max-children'},
'port|p=i' => \$opt{'port'},
'sql-config!' => \$opt{'sql-config'},
+ 'ldap-config!' => \$opt{'ldap-config'},
'q' => \$opt{'sql-config'},
'setuid-with-sql' => \$opt{'setuid-with-sql'},
+ 'setuid-with-ldap' => \$opt{'setuid-with-ldap'},
'Q' => \$opt{'setuid-with-sql'},
'virtual-config|V=s' => \$opt{'virtual-config'},
'virtual-config-dir=s' => \$opt{'virtual-config-dir'},
@@ -665,11 +667,16 @@
{
if ($opt{'sql-config'}) {
handle_user_sql($current_user);
+ } elsif ($opt{'ldap-config'}) {
+ handle_user_ldap($current_user);
} elsif ($opt{'virtual-config'} || $opt{'virtual-config-dir'}) {
handle_virtual_user($current_user);
} elsif ($opt{'setuid-with-sql'}) {
handle_user_setuid_with_sql($current_user);
$setuid_to_user = 1; #to benefit from any paranoia.
+ } elsif ($opt{'setuid-with-ldap'}) {
+ handle_user_setuid_with_ldap($current_user);
+ $setuid_to_user = 1; # as above
}
} else {
handle_user($current_user);
@@ -714,6 +721,10 @@
handle_user_sql('nobody');
}

+ if ($opt{'ldap-config'} && !defined($current_user)) {
+ handle_user_ldap('nobody');
+ }
+
my $resp = "EX_OK";

# Now read in message
@@ -991,7 +1002,7 @@
}

# Handle user configs without the necessity of having individual users or a
-# SQL database.
+# SQL/LDAP database.
sub handle_virtual_user
{
my $username = shift;
@@ -1057,6 +1068,14 @@
return 1;
}

+sub handle_user_ldap
+{
+ my $username = shift;
+ Mail::SpamAssassin::dbg("handle_user_ldap($username)");
+ $spamtest->load_scoreonly_ldap ($username);
+ return 1;
+}
+
sub handle_user_setuid_with_sql
{
my $username = shift;
@@ -1105,6 +1124,51 @@
return 1;
}

+sub handle_user_setuid_with_ldap
+{
+ my $username = shift;
+ my ($name,$pwd,$uid,$gid,$quota,$comment,$gcos,$dir,$etc) = getpwnam($username);
+
+ if ( !$spamtest->{'paranoid'} && !defined($uid) ) {
+ #if we are given a username, but can't look it up,
+ #Maybe NIS is down? lets break out here to allow
+ #them to get 'defaults' when we are not running paranoid.
+ logmsg "handle_user() -> unable to find user [$username]!\n";
+ return 0;
+ }
+
+ if ($setuid_to_user) {
+ $) = "$gid $gid"; # change eGID
+ $> = $uid; # change eUID
+ if ( !defined($uid) || ($> != $uid and $> != ($uid-2**32))) {
+ logmsg "fatal: setuid to $username failed";
+ die; # make it fatal to avoid security breaches
+ }
+ else
+ {
+ logmsg "info: setuid to $username succeeded, reading scores from LDAP.";
+ }
+ }
+
+ my $spam_conf_dir = $dir . '/.spamassassin'; #needed for AWL, Bayes, etc.
+ if ( ! -d $spam_conf_dir )
+ {
+ if ( mkdir $spam_conf_dir, 0700 )
+ {
+ logmsg "info: created $spam_conf_dir for $username.";
+ }
+ else
+ {
+ logmsg "info: failed to create $spam_conf_dir for $username.";
+ }
+ }
+
+ $spamtest->load_scoreonly_ldap ($username);
+
+ $spamtest->signal_user_changed ({ username => $username });
+ return 1;
+}
+
sub create_default_cf_if_needed {
my ($cf_file, $username, $userdir) = @_;

@@ -1337,6 +1401,9 @@
-q, --sql-config Enable SQL config (only useful with -x)
-Q, --setuid-with-sql Enable SQL config (only useful with -x,
enables use of -H)
+ --ldap-config Enable LDAP config (only useful with -x)
+ --setuid-with-ldap Enable LDAP config (only useful with -x,
+ enables use of -a and -H)
-V, --virtual-config=dir Enable Virtual configs (needs -x)
--virtual-config-dir=dir Enable pattern based Virtual configs (needs -x)
-r pidfile, --pidfile Write the process id to pidfile
@@ -1429,6 +1496,11 @@
If your spamc client does not support sending the C<User:> header,
like C<exiscan>, then the SQL username used will always be B<nobody>.

+=item B<--ldap-config>
+
+Turn on LDAP lookups. This is completely analog to C<--sql-config>,
+only it is using an LDAP server.
+
=item B<-Q>, B<--setuid-with-sql>

Turn on SQL lookups even when per-user config files have been disabled
@@ -1436,6 +1508,12 @@
which want to load user preferences from an SQL database but also wish to
support the use of B<-a> (AWL) and B<-H> (Helper home directories.)

+=item B<--setuid-with-ldap>
+
+Turn on LDAP lookups even when per-user config files have been disabled
+with B<-x> and also setuid to the user. This is again completely analog
+to C<--setuid-with-sql>, only it is using an LDAP server.
+
=item B<--virtual-config-dir>=I<pattern>

This option specifies where per-user preferences can be found for virtual
@@ -1476,7 +1554,7 @@
databases for that user will be stored in this directory.

Note that this B<requires> that B<-x> is used, and cannot be combined with
-SQL-based configuration.
+SQL- or LDAP-based configuration.

The pattern B<must> expand to an absolute directory when spamd is running
daemonized (B<-d>).
@@ -1497,7 +1575,7 @@
All others will be replaced by underscores (C<_>).

Note that this B<requires> that B<-x> is used, and cannot be combined with
-SQL-based configuration.
+SQL- or LDAP-based configuration.

If a subdirectory is found in that directory, called B<I<username>>, and it is
writable, it will be used to store auto-whitelist and/or Bayes databases for

Added: incubator/spamassassin/trunk/t/spamd_ldap.t
==============================================================================
--- (empty file)
+++ incubator/spamassassin/trunk/t/spamd_ldap.t Thu Feb 5 22:49:55 2004
@@ -0,0 +1,37 @@
+#!/usr/bin/perl
+#
+# NOTE: requires setup as per ldap/README.testing in advance
+
+use lib '.'; use lib 't';
+use SATest; sa_t_init("spamd_ldap");
+
+use constant TEST_ENABLED => (-e 't/do_ldap' || -e 'do_ldap');
+
+use Test; BEGIN { plan tests => (TEST_ENABLED ? 8 : 0) };
+
+exit unless (TEST_ENABLED);
+
+# ---------------------------------------------------------------------------
+
+%patterns = (
+
+q{ Subject: There yours for FREE!}, 'subj',
+q{ X-Spam-Status: Yes, hits=}, 'status',
+q{ X-Spam-Flag: YES}, 'flag',
+q{ X-Spam-Level: **********}, 'stars',
+q{ X-Spam-Foo: LDAP read}, 'ldap_config_read',
+q{ FROM_ENDS_IN_NUMS}, 'endsinnums',
+q{ NO_REAL_NAME}, 'noreal',
+
+
+);
+
+tstlocalrules ("
+ user_scores_dsn ldap://localhost/o=stooges?spamassassin?sub?uid=__USERNAME__
+ user_scores_ldap_username cn=StoogeAdmin,o=stooges
+ user_scores_ldap_password secret1
+");
+
+ok (sdrun ("-L --ldap-config", "-u curley < data/spam/001", \&patterns_run_cb));
+ok_all_patterns();
+