2012-04-29 10:35:59 +02:00
|
|
|
#!perl -w
|
2010-05-08 19:25:08 +02:00
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings;
|
2012-05-04 22:04:28 +02:00
|
|
|
|
|
|
|
use Qpsmtpd::Constants;
|
2010-05-08 19:25:08 +02:00
|
|
|
use IO::Socket;
|
2013-04-21 06:50:39 +02:00
|
|
|
use version;
|
2013-04-26 00:51:34 +02:00
|
|
|
my $VERSION = qv('1.0.4');
|
2010-05-08 19:25:08 +02:00
|
|
|
|
|
|
|
sub register {
|
|
|
|
my ($self, $qp, %args) = @_;
|
|
|
|
|
2012-04-07 23:52:44 +02:00
|
|
|
$self->{_vpopmaild_host} = $args{host} || 'localhost';
|
|
|
|
$self->{_vpopmaild_port} = $args{port} || '89';
|
2010-05-08 19:25:08 +02:00
|
|
|
|
|
|
|
$self->register_hook('auth-plain', 'auth_vpopmaild');
|
|
|
|
$self->register_hook('auth-login', 'auth_vpopmaild');
|
2013-04-21 06:50:39 +02:00
|
|
|
|
2012-05-04 22:04:28 +02:00
|
|
|
#$self->register_hook('auth-cram-md5', 'auth_vpopmaild'); # not supported
|
2010-05-08 19:25:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sub auth_vpopmaild {
|
2013-04-21 06:50:39 +02:00
|
|
|
my ($self, $transaction, $method, $user, $passClear, $passHash, $ticket) =
|
|
|
|
@_;
|
2012-04-07 23:52:44 +02:00
|
|
|
|
2013-04-21 06:50:39 +02:00
|
|
|
if (!$passClear) {
|
2012-05-15 06:48:55 +02:00
|
|
|
$self->log(LOGINFO, "skip: vpopmaild does not support cram-md5");
|
2012-05-04 22:04:28 +02:00
|
|
|
return DECLINED;
|
|
|
|
}
|
2010-05-08 19:25:08 +02:00
|
|
|
|
2013-04-26 00:51:34 +02:00
|
|
|
my $socket = $self->get_socket() or return DECLINED;
|
2010-05-08 19:25:08 +02:00
|
|
|
|
2012-05-04 22:04:28 +02:00
|
|
|
$self->log(LOGDEBUG, "attempting $method");
|
2012-04-07 23:52:44 +02:00
|
|
|
|
2010-05-08 19:25:08 +02:00
|
|
|
# Get server greeting (+OK)
|
2013-04-26 00:51:34 +02:00
|
|
|
my $response = $self->get_response( $socket, '' )
|
|
|
|
or return DECLINED;
|
2010-05-08 19:25:08 +02:00
|
|
|
|
2013-04-26 00:51:34 +02:00
|
|
|
if ($response !~ /^\+OK/) {
|
|
|
|
$self->log(LOGERROR, "skip, bad connection response: $response");
|
|
|
|
close $socket;
|
2012-05-04 22:04:28 +02:00
|
|
|
return DECLINED;
|
2013-04-21 06:50:39 +02:00
|
|
|
}
|
2010-05-08 19:25:08 +02:00
|
|
|
|
2013-04-26 00:51:34 +02:00
|
|
|
print $socket "login $user $passClear\n\r"; # send login details
|
|
|
|
$response = $self->get_response( $socket, "login $user $passClear\n\r" )
|
|
|
|
or return DECLINED;
|
2010-05-08 19:25:08 +02:00
|
|
|
|
2013-04-26 00:51:34 +02:00
|
|
|
close $socket;
|
2012-05-04 22:04:28 +02:00
|
|
|
|
2012-04-07 23:52:44 +02:00
|
|
|
# check for successful login (single line (+OK) or multiline (+OK+))
|
2013-04-26 00:51:34 +02:00
|
|
|
if ($response =~ /^\+OK/) {
|
|
|
|
$self->log(LOGINFO, "pass, clear");
|
2012-05-04 22:04:28 +02:00
|
|
|
return (OK, 'auth_vpopmaild');
|
2013-04-21 06:50:39 +02:00
|
|
|
}
|
2012-04-07 23:52:44 +02:00
|
|
|
|
2013-04-26 00:51:34 +02:00
|
|
|
chomp $response;
|
|
|
|
$self->log(LOGNOTICE, "fail, $response");
|
2012-04-07 23:52:44 +02:00
|
|
|
return DECLINED;
|
2010-05-08 19:25:08 +02:00
|
|
|
}
|
|
|
|
|
2013-04-26 00:51:34 +02:00
|
|
|
sub get_response {
|
|
|
|
my ($self, $socket, $send) = @_;
|
|
|
|
|
|
|
|
print $socket $send if $send; # send request
|
|
|
|
my $response = <$socket>; # get response
|
|
|
|
chomp $response;
|
|
|
|
|
|
|
|
if ( ! defined $response ) {
|
|
|
|
$self->log(LOGERROR, "error, no connection response");
|
|
|
|
close $socket;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($response =~ /^([ -~\n\r]+)$/) { # match ascii printable
|
|
|
|
$response = $1; # $response now untainted
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$self->log(LOGERROR, "error, response unsafe.");
|
|
|
|
};
|
|
|
|
|
|
|
|
return $response;
|
|
|
|
};
|
|
|
|
|
|
|
|
sub get_socket {
|
|
|
|
my ($self) = @_;
|
|
|
|
|
|
|
|
# create socket
|
|
|
|
my $socket =
|
|
|
|
IO::Socket::INET->new(
|
|
|
|
PeerAddr => $self->{_vpopmaild_host},
|
|
|
|
PeerPort => $self->{_vpopmaild_port},
|
|
|
|
Proto => 'tcp',
|
|
|
|
Type => SOCK_STREAM
|
|
|
|
)
|
|
|
|
or do {
|
|
|
|
$self->log(LOGERROR, "skip, socket connection to vpopmaild failed");
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
return $socket;
|
|
|
|
};
|
|
|
|
|
2010-05-08 19:25:08 +02:00
|
|
|
__END__
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
|
|
|
auth_vpopmaild - Authenticate to vpopmaild
|
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
|
|
|
Authenticates the user against against vpopmaild [1] daemon.
|
|
|
|
|
|
|
|
=head1 CONFIGURATION
|
|
|
|
|
|
|
|
Add a line to C<config/plugins> as follows:
|
|
|
|
|
|
|
|
auth_vpopmaild
|
|
|
|
|
|
|
|
By default, the plugin connects to localhot on port 89. If your vpopmaild
|
|
|
|
daemon is running on a different host or port, specify as follows:
|
|
|
|
|
|
|
|
auth_vpopmaild host [host] port [port]
|
|
|
|
|
2010-05-11 08:19:05 +02:00
|
|
|
=head1 SEE ALSO
|
|
|
|
|
|
|
|
For an overview of the vpopmail authentication plugins and their merits,
|
|
|
|
please read the VPOPMAIL section in doc/authentication.pod
|
|
|
|
|
2010-05-08 19:25:08 +02:00
|
|
|
=head1 LINKS
|
|
|
|
|
|
|
|
[1] http://www.qmailwiki.org/Vpopmaild
|
|
|
|
|
|
|
|
=head1 AUTHOR
|
|
|
|
|
|
|
|
Robin Bowes <robin.bowes@yo61.com>
|
|
|
|
|
2013-04-26 00:51:34 +02:00
|
|
|
2012 Matt Simerson (updated response parsing, added logging)
|
|
|
|
|
|
|
|
2013 Matt Simerson - split get_response and get_socket into new methods, added taint checking to responses
|
2012-04-07 23:52:44 +02:00
|
|
|
|
2010-05-08 19:25:08 +02:00
|
|
|
=head1 COPYRIGHT AND LICENSE
|
|
|
|
|
|
|
|
Copyright (c) 2010 Robin Bowes
|
|
|
|
|
|
|
|
This plugin is licensed under the same terms as the qpsmtpd package itself.
|
|
|
|
Please see the LICENSE file included with qpsmtpd for details.
|
|
|
|
|
|
|
|
=cut
|