Added SQL and LDAP page

This commit is contained in:
Jamie Cameron
2007-10-08 05:29:46 +00:00
parent b53936a30f
commit 71ceafc07a
9 changed files with 223 additions and 8 deletions

View File

@@ -8,3 +8,5 @@ Updated the setup and procmail delivery pages to allow forwarding of spam to an
Added a Module Config option for specifying a command other than spamassassin (such as spamc) to use in the procmailrc file. This defaults to an automatic mode, where spamc is used if spamd is running.
---- Changes since 1.300 ----
Added Module Config options for commands to run before and after saving SpamAssassin config changes.
---- Changes since 1.360 ----
Added the SQL and LDAP Databases page for configuring SpamAssassin to use a MySQL, PostgreSQL or LDAP database for user preferences.

View File

@@ -8,7 +8,8 @@ sub acl_security_form
print "<tr> <td valign=top><b>$text{'acl_avail'}</b></td>\n";
print "<td><select name=avail rows=6 multiple>\n";
local %avail = map { $_, 1 } split(/,/, $_[0]->{'avail'});
foreach $a ('white', 'score', 'report', 'user', 'header', 'setup', 'procmail') {
foreach $a ('white', 'score', 'report', 'user', 'header', 'setup', 'procmail',
'db') {
printf "<option value=%s %s>%s\n",
$a, $avail{$a} ? "selected" : "", $text{$a."_title"};
}

View File

@@ -1 +1 @@
avail=white,score,report,user,header,priv,setup,procmail
avail=white,score,report,user,header,priv,setup,procmail,db

107
spam/edit_db.cgi Executable file
View File

@@ -0,0 +1,107 @@
#!/usr/local/bin/perl
# Show form for SpamAssassin DB options
require './spam-lib.pl';
&can_use_check("db");
&ui_print_header(undef, $text{'db_title'}, "");
$conf = &get_config();
print "$text{'db_desc'}<p>\n";
&start_form("save_db.cgi", $text{'db_header'});
# Work out backend type
$dsn = &find_value("user_scores_dsn", $conf);
if ($dsn =~ /^DBI:([^:]+):([^:]+):([^:]+)(:(\d+))?$/) {
# To database
$mode = 1;
($dbdriver, $dbdb, $dbhost, $dbport) = ($1, $2, $3, $5);
}
elsif ($dsn =~ /^ldap:\/\/([^:]+)(:(\d+))?\/([^\?]+)\?([^\?]+)\?([^\?]+)\?([^=]+)=__USERNAME__/) {
# To LDAP
$mode = 3;
($ldaphost, $ldapport, $ldapdn, $ldapattr, $ldapscope, $ldapuid) =
($1, $3, $4, $5, $6, $7);
}
elsif ($dsn) {
$mode = 4;
}
else {
$mode = 0;
}
# Generate input blocks for SQL and LDAP
$dbtable = &ui_table_start(undef, undef, 2, [ "nowrap" ]);
$dbtable .= &ui_table_row($text{'db_dbdriver'},
&ui_select("dbdriver", $dbdriver || "mysql",
[ [ "mysql", "MySQL" ], [ "Pg", "PostgreSQL" ] ],
1, 0, 1));
$dbtable .= &ui_table_row($text{'db_dbhost'},
&ui_textbox("dbhost", $dbhost, 40));
$dbtable .= &ui_table_row($text{'db_dbdb'},
&ui_textbox("dbdb", $dbdb, 40));
$dbtable .= &ui_table_row($text{'db_dbport'},
&ui_opt_textbox("dbport", $dbport, 5, $text{'default'}));
$dbtable .= &ui_table_end();
$ldaptable = &ui_table_start(undef, undef, 2, [ "nowrap" ]);
$ldaptable .= &ui_table_row($text{'db_ldaphost'},
&ui_textbox("ldaphost", $ldaphost, 40));
$ldaptable .= &ui_table_row($text{'db_ldapport'},
&ui_opt_textbox("ldapport", $ldapport, 5, $text{'default'}));
$ldaptable .= &ui_table_row($text{'db_ldapdn'},
&ui_textbox("ldapdn", $ldapdn, 40));
$ldaptable .= &ui_table_row($text{'db_ldapattr'},
&ui_textbox("ldapattr", $ldapattr, 20));
$ldaptable .= &ui_table_row($text{'db_ldapscope'},
&ui_select("ldapscope", $ldapscope || "sub",
[ [ "sub", $text{'db_ldapsub'} ],
[ "one", $text{'db_ldapone'} ],
[ "base", $text{'db_ldapbase'} ] ], 1, 0, 1));
$ldaptable .= &ui_table_row($text{'db_ldapuid'},
&ui_textbox("ldapuid", $ldapuid || "uid", 20));
$ldaptable .= &ui_table_end();
# Show backend type selector
print "<tr> <td valign=top><b>$text{'db_dsn'}</b></td> <td nowrap>";
print &ui_radio_table("mode", $mode,
[ [ 0, $text{'db_mode0'} ],
[ 1, $text{'db_mode1'}, $dbtable ],
[ 3, $text{'db_mode3'}, $ldaptable ],
[ 4, $text{'db_mode4'},
&ui_textbox("dsn", $dsn, 60) ] ]);
print "</td> </tr>\n";
print "<tr> <td colspan=2><hr></td> </tr>\n";
# DB login
print "<tr> <td><b>$text{'db_user'}</b></td> <td nowrap>";
$user = &find("user_scores_sql_username", $conf);
&opt_field("user_scores_sql_username", $user, 20, undef);
print "</td> </tr>\n";
# DB password
print "<tr> <td><b>$text{'db_pass'}</b></td> <td nowrap>";
$pass = &find("user_scores_sql_password", $conf);
&opt_field("user_scores_sql_password", $pass, 20, undef);
print "</td> </tr>\n";
print "<tr> <td colspan=2><hr></td> </tr>\n";
# LDAP login
print "<tr> <td><b>$text{'db_luser'}</b></td> <td nowrap>";
$user = &find("user_scores_ldap_username", $conf);
&opt_field("user_scores_ldap_username", $user, 40, undef);
print "</td> </tr>\n";
# LDAP password
print "<tr> <td><b>$text{'db_lpass'}</b></td> <td nowrap>";
$pass = &find("user_scores_ldap_password", $conf);
&opt_field("user_scores_ldap_password", $pass, 20, undef);
print "</td> </tr>\n";
&end_form(undef, $text{'save'});
&ui_print_footer("", $text{'index_return'});

BIN
spam/images/db.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -129,6 +129,7 @@ else {
push(@pages, 'razor') if (!$razor && $module_info{'usermin'});
push(@pages, 'setup') if ($spam_enabled == 0);
push(@pages, 'procmail') if ($delivery_enabled == 1);
push(@pages, 'db') if (!$module_info{'usermin'});
@pages = grep { &can_use_page($_) } @pages;
$sfolder = $module_info{'usermin'} ? &spam_file_folder()
: undef;

View File

@@ -295,3 +295,38 @@ connect_emysql=Failed to load the database driver $1
connect_elogin=Failed to login to the database $1 : $2.
connect_equery=The database $1 does not contain the preferences table $2
db_title=SQL and LDAP Databases
db_header=Configuration storage database options
db_dsn=Store user configurations in
db_mode0=Configuration files
db_mode1=SQL database
db_mode3=LDAP database
db_mode4=Other DSN
db_user=SQL database username
db_pass=SQL database password
db_luser=LDAP server username
db_lpass=LDAP server password
db_dbdriver=Database type
db_dbhost=Database server hostname
db_dbdb=Database name
db_dbport=Port number
db_err=Failed to save databases
db_edbhost=Missing or invalid SQL server hostname
db_edbdb=Missing or invalid-looking database name
db_edbport=Missing or invalid SQL server port number
db_edsn=Missing other DSN
db_eusername=Missing or invalid database username - no spaces are allowed
db_ldaphost=LDAP server hostname
db_ldapport=Port number
db_ldapdn=Base DN for users
db_ldapattr=Attribute for SpamAssassin preferences
db_ldapscope=Search depth
db_ldapsub=Entire subtree
db_ldapone=One level
db_ldapbase=Base only
db_ldapuid=Attribute for username
db_eldaphost=Missing or invalid LDAP server hostname
db_eldapport=Missing or invalid LDAP server port number
db_eldapdn=Missing or invalid base DN - no spaces are allowed
db_eldapattr=Missing or invalid SpamAssassin attribute
db_eldapuid=Missing or invalid username attribute

62
spam/save_db.cgi Executable file
View File

@@ -0,0 +1,62 @@
#!/usr/local/bin/perl
# Save LDAP and SQL database options
require './spam-lib.pl';
&error_setup($text{'db_err'});
&can_use_check("db");
&ReadParse();
&execute_before("db");
&lock_spam_files();
$conf = &get_config();
# Parse backend DSN
if ($in{'mode'} == 0) {
# Files only
$dsn = undef;
}
elsif ($in{'mode'} == 1) {
# Database of some type
gethostbyname($in{'dbhost'}) || &error($text{'db_edbhost'});
$in{'dbdb'} =~ /^[a-z0-9\.\-\_]+$/ || &error($text{'db_edbdb'});
$in{'dbport_def'} || $in{'dbport'} =~ /^\d+$/ ||
&error($text{'db_edbport'});
$dsn = join(":", "DBI", $in{'dbdriver'}, $in{'dbdb'}, $in{'dbhost'});
$dsn .= ":".$in{'dbport'} if (!$in{'dbport_def'});
}
elsif ($in{'mode'} == 3) {
# LDAP
gethostbyname($in{'ldaphost'}) || &error($text{'db_eldaphost'});
$in{'ldapport_def'} || $in{'ldapport'} =~ /^\d+$/ ||
&error($text{'db_eldapport'});
$in{'ldapdn'} =~ /^\S+$/ || &error($text{'db_eldapdn'});
$in{'ldapattr'} =~ /^\S+$/ || &error($text{'db_eldapattr'});
$in{'ldapuid'} =~ /^\S+$/ || &error($text{'db_eldapuid'});
$dsn = "ldap://".$in{'ldaphost'}.
($in{'ldapport_def'} ? "" : ":".$in{'ldapport'})."/".
$in{'ldapdn'}."?".$in{'ldapattr'}."?".$in{'ldapscope'}."?".
$in{'ldapuid'}."=__USERNAME__";
}
else {
# Other DSN
$in{'dsn'} =~ /\S/ || &error($text{'db_edsn'});
$dsn = $in{'dsn'};
}
&save_directives($conf, "user_scores_dsn", [ $dsn ], 1);
# Parse username and password
&parse_opt($conf, "user_scores_sql_username", \&username_check);
&parse_opt($conf, "user_scores_sql_password");
&parse_opt($conf, "user_scores_ldap_username", \&username_check);
&parse_opt($conf, "user_scores_ldap_password");
&flush_file_lines();
&unlock_spam_files();
&execute_after("db");
&webmin_log("db");
&redirect("");
sub username_check
{
return $_[0] =~ /^\S+$/ ? undef : $text{'db_eusername'};
}

View File

@@ -20,7 +20,7 @@ if ($module_info{'usermin'}) {
}
}
$database_userpref_name = $remote_user;
$include_config_files = 1; # XXX
$include_config_files = $config{'readfiles'};
$add_to_db = 1;
}
else {
@@ -40,12 +40,13 @@ $add_cf = !-d $local_cf ? $local_cf :
$module_info{'usermin'} ? "$local_cf/user_prefs" :
"$local_cf/local.cf";
# get_config([file])
# get_config([file], [for-global])
# Return a structure containing the contents of the spamassassin config file
sub get_config
{
local $forglobal = $_[1];
local @rv;
if ($include_config_files) {
if ($include_config_files || $forglobal) {
# Reading from file(s)
local $lnum = 0;
local $file = $_[0] || $local_cf;
@@ -91,10 +92,12 @@ if ($config{'mode'} == 1 || $config{'mode'} == 2) {
local $dbh = &connect_spamassasin_db();
&error($dbh) if (!ref($dbh));
local $cmd = $dbh->prepare("select preference,value from userpref where username = ?");
$cmd->execute($database_userpref_name);
$cmd->execute(!$forglobal ? $database_userpref_name :
$config{'dbglobal'} ? $config{'dbglobal'} : '@GLOBAL');
while(my ($name, $value) = $cmd->fetchrow()) {
local $dir = { 'name' => $name,
'value' => $value,
'index' => scalar(@rv),
'mode' => $config{'mode'} };
$dir->{'words'} =
[ split(/\s+/, $dir->{'value'}) ];
@@ -210,6 +213,7 @@ for($i=0; $i<@old || $i<@new; $i++) {
elsif ($new[$i]) {
# Adding a directive
local $addmode = scalar(@old) ? $old[0]->{'mode'} :
$new[$i]->{'name'} =~ /^user_scores_/ ? 0 :
$add_to_db ? $config{'mode'} : 0;
if ($addmode == 0) {
# To a file
@@ -231,6 +235,7 @@ for($i=0; $i<@old || $i<@new; $i++) {
# To LDAP
# XXX
}
$new[$i]->{'mode'} = $addmode;
$new[$i]->{'index'} = @{$_[0]};
push(@{$_[0]}, $new[$i]);
}
@@ -430,8 +435,10 @@ else {
sub find_default
{
if ($config{'global_cf'}) {
local $gconf = &get_config($config{'global_cf'});
local $v = &find_value($_[0], $gconf);
if (!defined($global_config_cache)) {
$global_config_cache = &get_config($config{'global_cf'}, 1);
}
local $v = &find_value($_[0], $global_config_cache);
return $v if (defined($v));
}
return $_[1];