my
$server
= Apache2::ServerUtil->server() or
die
'serverutil->server'
;
$server
->push_handlers(
PerlPostConfigHandler
=> [\
&post_config
, \
&add_version_string
,],);
qw(OK RSRC_CONF ITERATE ITERATE2 FLAG TAKE1 TAKE2 :log SERVER_ERROR)
;
{
my
@directives
;
push
@directives
, {
name
=>
'SAEnabled'
,
args_how
=> Apache2::Const::FLAG,
req_override
=> Apache2::Const::RSRC_CONF,
errmsg
=>
'SAEnable { On | Off }'
,
};
push
@directives
, {
name
=>
'SAAllow'
,
args_how
=> Apache2::Const::ITERATE2,
req_override
=> Apache2::Const::RSRC_CONF,
errmsg
=>
'SAAllow from 127.0.0.1 192.168/16 ::1 ...'
,
};
push
@directives
, {
name
=>
'SAIdent'
,
args_how
=> Apache2::Const::FLAG,
req_override
=> Apache2::Const::RSRC_CONF,
errmsg
=>
'SAIdent { On | Off }'
,
};
push
@directives
, {
name
=>
'SATell'
,
args_how
=> Apache2::Const::FLAG,
req_override
=> Apache2::Const::RSRC_CONF,
errmsg
=>
'SATell { On | Off }'
,
};
push
@directives
, {
name
=>
'SATimeout'
,
args_how
=> Apache2::Const::TAKE1,
req_override
=> Apache2::Const::RSRC_CONF,
errmsg
=>
'SATimeout 300 # unit: seconds'
,
};
push
@directives
, {
name
=>
'SADebug'
,
args_how
=> Apache2::Const::TAKE1,
req_override
=> Apache2::Const::RSRC_CONF,
errmsg
=>
'SADebug { debug_level | 0 }'
,
};
push
@directives
, {
name
=>
'SAMsgSizeLimit'
,
args_how
=> Apache2::Const::TAKE1,
req_override
=> Apache2::Const::RSRC_CONF,
errmsg
=>
'SAMsgSizeLimit limit_in_bytes'
,
};
push
@directives
, {
name
=>
'SANew'
,
args_how
=> Apache2::Const::TAKE2,
req_override
=> Apache2::Const::RSRC_CONF,
errmsg
=>
'SANew rules_filename "/some/path"'
,
};
push
@directives
, {
name
=>
'SAUsers'
,
args_how
=> Apache2::Const::ITERATE,
req_override
=> Apache2::Const::RSRC_CONF,
errmsg
=>
'SAUsers { none | local | sql | ldap }'
,
};
push
@directives
, {
name
=>
'SALocale'
,
args_how
=> Apache2::Const::TAKE1,
req_override
=> Apache2::Const::RSRC_CONF,
errmsg
=>
'SALocale xx_XX'
,
};
push
@directives
, {
name
=>
'SAConfigLine'
,
args_how
=> Apache2::Const::TAKE1,
req_override
=> Apache2::Const::RSRC_CONF,
errmsg
=>
'SAConfigLine "body NEWRULE /text/"'
,
};
Apache2::Module::add(__PACKAGE__, \
@directives
);
}
sub
SAEnabled {
my
(
$self
,
$parms
,
$arg
) =
@_
;
my
$srv_cfg
= Apache2::Module::get_config(
$self
,
$parms
->server);
$srv_cfg
->{saenabled} =
$arg
;
}
sub
SAAllow {
my
(
$self
,
$parms
,
$key
,
$val
) =
@_
;
die
'usage: SAAllow from ... ... ...'
unless
$key
eq
'from'
;
my
$srv_cfg
= Apache2::Module::get_config(
$self
,
$parms
->server);
push
@{
$srv_cfg
->{allowed_ips} },
$val
;
}
sub
SAIdent {
my
(
$self
,
$parms
,
$arg
) =
@_
;
my
$srv_cfg
= Apache2::Module::get_config(
$self
,
$parms
->server);
$srv_cfg
->{auth_ident} =
$arg
;
}
sub
SATell {
my
(
$self
,
$parms
,
$arg
) =
@_
;
my
$srv_cfg
= Apache2::Module::get_config(
$self
,
$parms
->server);
$srv_cfg
->{allow_tell} =
$arg
;
}
sub
SATimeout {
my
(
$self
,
$parms
,
$arg
) =
@_
;
die
"SATimeout accepts *seconds*\n"
if
$arg
!~ /^\d+$/;
my
$srv_cfg
= Apache2::Module::get_config(
$self
,
$parms
->server);
$srv_cfg
->{satimeout} =
$arg
;
}
sub
SADebug {
my
(
$self
,
$parms
,
$arg
) =
@_
;
die
"SADebug can't be used in vhost, see bug #4963\n"
if
$parms
->server->is_virtual;
my
$srv_cfg
= Apache2::Module::get_config(
$self
,
$parms
->server);
$srv_cfg
->{sa_debug} =
$arg
;
}
sub
SAMsgSizeLimit {
my
(
$self
,
$parms
,
$arg
) =
@_
;
die
"MsgSizeLimit accepts *number*\n"
if
$arg
!~ /^\d+$/;
my
$srv_cfg
= Apache2::Module::get_config(
$self
,
$parms
->server);
$srv_cfg
->{msg_size_limit} =
$arg
;
}
sub
SANew {
my
(
$self
,
$parms
,
$key
,
$val
) =
@_
;
die
"SANew can't be used in vhost, see bug #4963\n"
if
$parms
->server->is_virtual;
my
$srv_cfg
= Apache2::Module::get_config(
$self
,
$parms
->server);
$srv_cfg
->{sa_args_to_new}->{
$key
} =
$val
;
}
sub
SAUsers {
my
(
$self
,
$parms
,
$arg
) =
@_
;
$arg
=
lc
$arg
;
die
"SAUsers: bad value\n"
unless
$arg
=~ /^(?:none|
local
|sql|ldap)$/;
my
$srv_cfg
= Apache2::Module::get_config(
$self
,
$parms
->server);
push
@{
$srv_cfg
->{sa_users} },
$arg
;
}
sub
SALocale {
my
(
$self
,
$parms
,
$arg
) =
@_
;
die
"SALocale can't be used in vhost, see bug #4963\n"
if
$parms
->server->is_virtual;
my
$srv_cfg
= Apache2::Module::get_config(
$self
,
$parms
->server);
$srv_cfg
->{sa_locale} =
$arg
;
}
sub
SAConfigLine {
my
(
$self
,
$parms
,
$arg
) =
@_
;
my
$srv_cfg
= Apache2::Module::get_config(
$self
,
$parms
->server);
$srv_cfg
->{post_config_text} .=
(
$srv_cfg
->{post_config_text} ?
"\n"
:
''
) .
$arg
;
}
sub
SERVER_CREATE {
my
(
$class
,
$parms
) =
@_
;
bless
{
saenabled
=> 0,
satimeout
=> 300, },
$class
;
}
sub
SERVER_MERGE {
my
(
$base
,
$add
) =
@_
;
my
$new
= {
saenabled
=>
$add
->{saenabled}, };
$new
->{allowed_ips} =
exists
$add
->{allowed_ips} ? [@{
$add
->{allowed_ips} }]
:
exists
$base
->{allowed_ips} ? [@{
$base
->{allowed_ips} }]
: [
warn
(
'warning: access denied for everyone in vhost'
) && ()];
for
my
$opt
(
qw(auth_ident ident_timeout allow_tell
sa_debug sa_args_to_new sa_users sa_locale)
)
{
$new
->{
$opt
} =
exists
$add
->{
$opt
} ?
$add
->{
$opt
}
:
exists
$base
->{
$opt
} ?
$base
->{
$opt
}
: 0;
}
$new
->{satimeout} =
exists
$add
->{satimeout} ?
$add
->{satimeout}
:
exists
$base
->{satimeout} ?
$base
->{satimeout}
:
die
'should not happen'
;
bless
$new
,
ref
$base
;
}
sub
post_config {
my
(
$conf_pool
,
$log_pool
,
$temp_pool
,
$serv
) =
@_
;
my
(
$num_vhosts
,
$num_configured
);
my
$hackish_tmp_ref
;
for
(
my
$s
=
$serv
;
$s
;
$s
=
$s
->
next
) {
die
"\$num_vhosts>5000; loop?"
if
++
$num_vhosts
> 1000;
my
$srv_cfg
= Apache2::Module::get_config(__PACKAGE__,
$s
) ||
''
;
$hackish_tmp_ref
=
$srv_cfg
unless
$s
->is_virtual;
if
(!
$srv_cfg
->{saenabled}
or
$s
->is_virtual &&
$srv_cfg
eq
$hackish_tmp_ref
)
{
my
$msg
=
'SAEnabled off for '
. _vhost_id(
$s
);
$msg
.=
' and on in default server; it probably won\'t work as'
.
' you intend it to -- either Apache or this code is broken'
if
$hackish_tmp_ref
->{saenabled} &&
$srv_cfg
&& !
$srv_cfg
->{saenabled};
$s
->log_serror(Apache2::Log::LOG_MARK(),
Apache2::Const::LOG_DEBUG | Apache2::Const::LOG_STARTUP,
APR::Const::SUCCESS,
$msg
);
next
;
}
if
(
ref
$srv_cfg
->{sa_users}
&&
grep
{
$_
eq
'none'
} @{
$srv_cfg
->{sa_users} })
{
if
(@{
$srv_cfg
->{sa_users} } > 1) {
die
"if you add 'none' to SAUsers, it's pointless to add anything else\n"
;
}
else
{
delete
$srv_cfg
->{sa_users};
}
}
for
my
$net
(@{
$srv_cfg
->{allowed_ips} }) {
my
$ais
= APR::IpSubnet->new(
$conf_pool
,
split
m
or
die
"APR::IpSubnet->new($net) failed"
;
push
@{
$srv_cfg
->{allowed_networks} },
$ais
;
}
my
@cfg
= (
'SetHandler modperl'
,
'PerlProcessConnectionHandler Mail::SpamAssassin::Spamd::Apache2'
,
'PerlPreConnectionHandler Mail::SpamAssassin::Spamd::Apache2::AclIP'
,
);
if
(
$srv_cfg
->{auth_ident}) {
push
@cfg
,
'PerlPreConnectionHandler '
.
'Mail::SpamAssassin::Spamd::Apache2::AclRFC1413'
;
}
$s
->add_config(\
@cfg
);
if
(!
$Mail::SpamAssassin::Spamd::Apache2::spamtest
) {
local
$/ = $/;
my
$sa
= Mail::SpamAssassin->new({
debug
=> (
$srv_cfg
->{sa_debug} || 0),
(
$srv_cfg
->{sa_args_to_new} ? %{
$srv_cfg
->{sa_args_to_new} } : ()),
}) or
die
'Mail::SpamAssassin->new() failed'
;
my
$tmphome
= File::Temp::tempdir()
or
die
"creating temp directory failed: $!"
;
my
$tmpsadir
= File::Spec->catdir(
$tmphome
,
'.spamassassin'
);
mkdir
$tmpsadir
, 0700 or
die
"spamd: cannot create $tmpsadir: $!"
;
$ENV
{HOME} =
$tmphome
;
$sa
->compile_now(0, 1);
delete
$ENV
{HOME};
system
(
"rm -rf '$tmphome'"
);
$Mail::SpamAssassin::Spamd::Apache2::spamtest
=
$sa
;
Mail::SpamAssassin::Spamd::backup_config(
$sa
);
}
$num_configured
++;
$s
->log_serror(Apache2::Log::LOG_MARK(),
Apache2::Const::LOG_DEBUG | Apache2::Const::LOG_STARTUP,
APR::Const::SUCCESS,
'spamd handler configured for '
,
_vhost_id(
$s
)
);
}
if
(!
$num_configured
) {
$serv
->log_serror(Apache2::Log::LOG_MARK(),
Apache2::Const::LOG_NOTICE | Apache2::Const::LOG_STARTUP,
APR::Const::EGENERAL,
'no spamd handlers configured'
);
}
return
Apache2::Const::OK;
}
sub
_vhost_id {
my
$s
=
shift
;
$s
->is_virtual()
?
'vhost '
.
$s
->server_hostname() .
':'
.
$s
->port()
:
'default server'
;
}
sub
add_version_string {
my
(
$conf_pool
,
$log_pool
,
$temp_pool
,
$serv
) =
@_
;
my
$version
= Mail::SpamAssassin->VERSION ||
'?'
;
$serv
->add_version_component(
"SpamAssassin/$version"
);
return
Apache2::Const::OK;
}
1;