diff --git a/plugins/auth/auth_cvm_unix_local b/plugins/auth/auth_cvm_unix_local new file mode 100644 index 0000000..dc4c7b7 --- /dev/null +++ b/plugins/auth/auth_cvm_unix_local @@ -0,0 +1,109 @@ +#!/usr/bin/perl -w + +=head1 NAME + +auth_cvm_unix_local - SMTP AUTH LOGIN module using +Bruce Guenther's Credential Validation Module (CVM) + http://untroubled.org/cvm/ + +=head1 SYNOPSIS + +In config/plugins: + + auth/auth_cvm_unix_local \ + cvm_socket /var/lib/cvm/cvm-unix-local.socket \ + enable_smtp no \ + enable_ssmtp yes + +=head1 BUGS + +- Should probably handle auth-cram-md5 as well. However, this requires +access to the plain text password. We could store a separate database +of passwords purely for SMTP AUTH, for example as an optional +SMTPAuthPassword property of an account in the esmith::AccountsDB; + +=head1 DESCRIPTION + +This plugin implements an authentication plugin using Bruce Guenther's +Credential Validation Module (http://untroubled.org/cvm). + +=head1 AUTHOR + +Copyright 2005 Gordon Rowell + +This software is free software and may be distributed or modified +under the same terms as Perl itself. + +=head1 VERSION + +Version $Id: auth_cvm_unix_local,v 1.1 2005/06/09 22:50:06 gordonr Exp gordonr $ + +=cut + +use Socket; +use constant SMTP_PORT => getservbyname("smtp", "tcp") || 25; +use constant SSMTP_PORT => getservbyname("ssmtp", "tcp") || 465; + +sub register +{ + my ( $self, $qp, %arg ) = @_; + + unless ($arg{cvm_socket}) + { + $self->log(LOGERROR, "authcvm - requires cvm_socket argument"); + return 0; + } + + $self->{_enable_smtp} = $arg{enable_smtp} || 'no'; + $self->{_enable_ssmtp} = $arg{enable_ssmtp} || 'yes'; + + my $port = $ENV{PORT} || SMTP_PORT; + + return 0 if ($port == SMTP_PORT and $self->{_enable_smtp} ne 'yes'); + return 0 if ($port == SSMTP_PORT and $self->{_enable_ssmtp} ne 'yes'); + + if ($arg{cvm_socket} =~ /^([\w\/.-]+)$/) + { + $self->{_cvm_socket} = $1; + } + + unless (-S $self->{_cvm_socket}) + { + $self->log(LOGERROR, "authcvm - cvm_socket missing or not usable"); + return 0; + } + + $self->register_hook("auth-plain", "authcvm_plain"); + $self->register_hook("auth-login", "authcvm_plain"); +# $self->register_hook("auth-cram-md5", "authcvm_hash"); +} + +sub authcvm_plain +{ + my ( $self, $transaction, $method, $user, $passClear, $passHash, $ticket ) = + @_; + + $self->log(LOGINFO, "authcvm/$method authentication attempt for: $user"); + + socket(SOCK, PF_UNIX, SOCK_STREAM, 0) + or return (DENY, "authcvm/$method"); + + connect(SOCK, sockaddr_un($self->{_cvm_socket})) + or return (DENY, "authcvm/$method"); + + my $o = select(SOCK); $| = 1; select($o); + + my ($u, $host) = split(/\@/, $user); + $host ||= "localhost"; + + print SOCK "\001$u\000$host\000$passClear\000\000"; + + shutdown SOCK, 1; + + my $ret = ; + my ($s) = unpack ("C", $ret); + return ( + ($s ? $s == 100 ? DENY : DECLINED + : OK), + "authcvm/$method"); +}