Hi,
setup summary:
spamc called from exim on a per-user-basis:
spamcheck:
driver = pipe
use_bsmtp = true
batch_max = 1
command = /usr/sbin/exim4 -oMr spam-scanned -bS
transport_filter = /usr/bin/spamc -u ${local_part} -U /var/run/spamd
user = Debian-exim
group = Debian-exim
...spamd: /usr/sbin/spamd --socketpath=/var/run/spamd ...
Of course, this is insecure, because any local user can call spamc on another local user's behalf.
To solve this, I've implemented
1.) SO_PEERCRED authentication for PF_UNIX sockets (including unsolved portability issue concerning "struct ucred" unpacking)
2.) a "trusted user" who may set any other user via the User: header if identified correctly
Thus, Debian-exim (trusted user) can use "-u $local_part" even with identification. Now the spamd command line becomes
/usr/sbin/spamd --socketpath=/var/run/spamd --auth-ident --trusted-user Debian-exim ...
I'll include the spamd diff just in case someone finds it useful. Of course, the --trusted-user option could be augmented to allow an array of trusted users.
Cheers, Enrik
--- spamassassin-3.0.2/spamd/spamd.raw 2004-10-22 17:21:26.000000000 +0200
+++ spamassassin-3.0.2-patched/spamd/spamd.raw 2005-01-27 15:58:08.000000000 +0100
@@ -176,6 +176,7 @@
'ssl' => \$opt{'ssl'},
'syslog-socket=s' => \$opt{'syslog-socket'},
'syslog|s=s' => \$opt{'syslog'},
+ 'trusted-user=s' => \$opt{'trusted-user'},
'user-config' => \$opt{'user-config'},
'username|u=s' => \$opt{'username'},
'version|V' => \$opt{'version'},
@@ -239,7 +240,6 @@
defined $opt{'socketpath'}
and ( ( @{ $opt{'allowed-ip'} } > 0 )
or defined $opt{'ssl'}
- or defined $opt{'auth-ident'}
or defined $opt{'port'} )
)
{
@@ -270,13 +270,20 @@
# ident-based spamc user authentication
if ( $opt{'auth-ident'} ) {
- eval { require Net::Ident };
- die
+ if (defined $opt{'socketpath'}) {
+ eval { my $dummy = SO_PEERCRED() };
+ die
+"fatal: peercred-based authentication requested, but SO_PEERCRED is unavailble\n"
+ if ($@);
+ } else {
+ eval { require Net::Ident };
+ die
"fatal: ident-based authentication requested, but Net::Ident is unavailable\n"
- if ($@);
+ if ($@);
- $opt{'ident-timeout'} = undef if $opt{'ident-timeout'} <= 0.0;
- import Net::Ident qw(ident_lookup);
+ $opt{'ident-timeout'} = undef if $opt{'ident-timeout'} <= 0.0;
+ import Net::Ident qw(ident_lookup);
+ }
}
# Check for server certs
@@ -1278,7 +1285,7 @@
}
$current_user = $1;
- if ($opt{'auth-ident'} && !auth_ident($current_user)) {
+ if ($opt{'auth-ident'} && !auth_ident($current_user, $opt{'trusted-user'})) {
return 1;
}
@@ -1347,15 +1354,40 @@
sub auth_ident {
my $username = shift;
- my $ident_username = ident_lookup( $client, $opt{'ident-timeout'} );
+ my $trusted = shift;
+ my $ident_username;
+ if (defined $opt{'socketpath'}) {
+ $ident_username = peercred_lookup( $client );
+ } else {
+ $ident_username = ident_lookup( $client, $opt{'ident-timeout'} );
+ }
my $dn = $ident_username || 'NONE'; # display name
- warn "ident_username = $dn, spamc_username = $username\n" if $opt{'debug'};
- if ( $username ne $ident_username ) {
- logmsg( "fatal: ident username ($dn) does not match "
- . "spamc username ($username)" );
- return 0;
+ if ( defined $trusted ) {
+ warn "ident_username = $dn, spamc_username = $username, trusted_username = $trusted\n" if $opt{'debug'};
+ } else {
+ warn "ident_username = $dn, spamc_username = $username\n" if $opt{'debug'};
}
- return 1;
+ if ( defined $trusted && $trusted eq $ident_username ||
+ $username eq $ident_username ) {
+ return 1;
+ }
+ logmsg( "fatal: ident username ($dn) does not match "
+ . "spamc username ($username)" );
+ return 0;
+}
+
+sub peercred_lookup {
+ my $sock = shift;
+ my $username;
+
+ # PF_UNIX "ident"
+ my $ucred = $sock->sockopt(SO_PEERCRED);
+ if (defined $ucred) {
+ # XXX portability
+ my ($pid, $uid, $gid) = unpack("I3", $ucred);
+ $username = ( getpwuid $uid )[0];
+ }
+ return $username;
}
sub handle_user {
@@ -1935,8 +1967,11 @@
-u username, --username=username Run as username
-v, --vpopmail Enable vpopmail config
-x, --nouser-config Disable user config files
- --auth-ident Use ident to authenticate spamc user
+ --auth-ident Use ident (tcp) or SO_PEERCRED (unix)
+ to authenticate spamc user
--ident-timeout=timeout Timeout for ident connections
+ --trusted-user=username Trust this user if identified, i.e. may
+ set abritrary usernames via protocol
-A host,..., --allowed-ips=..,.. Limit ip addresses which can connect
-D, --debug Print debugging messages
-L, --local Use local tests only (no DNS)
smime.p7s
Description: S/MIME Cryptographic Signature
