2010-05-11 01:07:48 +02:00
|
|
|
#!/usr/bin/perl -w
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
|
|
|
auth_checkpassword - Authenticate against a DJB style checkpassword program
|
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
|
|
|
This plugin authenticates users against a DJB style checkpassword
|
|
|
|
program. Unlike previous checkpassword implementations, this plugin
|
|
|
|
expects qpsmtpd to be running as the qpsmtpd user. Privilege
|
|
|
|
escalation can be attained by running the checkpassword binary setuid
|
|
|
|
or with sudo.
|
|
|
|
|
|
|
|
=head1 CONFIGURATION
|
|
|
|
|
|
|
|
Configure the path to your checkpassword binary:
|
|
|
|
|
|
|
|
echo "/usr/local/vpopmail/bin/vchkpw /usr/bin/true" > ~qpsmtpd/config/smtpauth-checkpassword
|
|
|
|
|
|
|
|
vchkpw is the checkpassword program provided by vpopmail. Substitute
|
|
|
|
your own checkpassword app as appropriate.
|
|
|
|
|
|
|
|
If you are using vchkpw and this plugin is being executed by a user ID
|
|
|
|
other than 89 or 0 (as is the default), and the vchkpw binary is not
|
|
|
|
setuid (as is the default), this plugin will automatically prepend the
|
|
|
|
vchkpw command with sudo. If that is the case, you must configure sudo
|
|
|
|
by adding these two lines to your sudoers file:
|
|
|
|
|
|
|
|
Defaults:qpsmtpd closefrom_override
|
|
|
|
qpsmtpd ALL = (ALL) NOPASSWD: /usr/local/vpopmail/bin/vchkpw
|
|
|
|
|
|
|
|
The closefrom_override option is necessary because, by default, sudo
|
|
|
|
appropriates the first 3 file descriptors. Those descriptors are
|
|
|
|
necessary to communicate with the checkpassword program. If you run
|
|
|
|
qpsmtpd as some other user, adjust the sudo lines approriately.
|
|
|
|
|
|
|
|
Using sudo is preferable to enabling setuid on the vchkpw binary. If
|
|
|
|
you reinstall vpopmail and the setuid bit is lost, this plugin will be
|
|
|
|
broken.
|
|
|
|
|
2010-05-11 08:19:05 +02:00
|
|
|
=head1 SEE ALSO
|
|
|
|
|
|
|
|
If you are using this plugin with vpopmail, please read the VPOPMAIL
|
|
|
|
section in docs/authentication.pod
|
|
|
|
|
2010-05-11 01:07:48 +02:00
|
|
|
=head1 DIAGNOSTICS
|
|
|
|
|
|
|
|
Is the path in the config/smtpauth-checkpassword correct?
|
|
|
|
|
|
|
|
Is the path to true in config/smtpauth-checkpassword correct?
|
|
|
|
|
|
|
|
Is qpsmtpd running as the qpsmtpd user? If not, did you adjust the
|
|
|
|
sudo configuration appropriately?
|
|
|
|
|
|
|
|
If you are not using sudo, did you remember to make the vchkpw binary
|
|
|
|
setuid (chmod 4711 ~vpopmail/bin/vchkpw)?
|
|
|
|
|
|
|
|
While writing this plugin, I first wrote myself a little test script,
|
|
|
|
which helped me identify the sudo closefrom_override issue. Here is
|
|
|
|
that script:
|
|
|
|
|
|
|
|
#!/usr/bin/perl
|
|
|
|
use strict;
|
|
|
|
my $sudo = "/usr/local/bin/sudo";
|
|
|
|
$sudo .= " -C4 -u vpopmail";
|
|
|
|
my $vchkpw = "/usr/local/vpopmail/bin/vchkpw";
|
|
|
|
my $true = "/usr/bin/true";
|
|
|
|
|
|
|
|
open(CPW,"|$sudo $vchkpw $true 3<&0");
|
|
|
|
printf(CPW "%s\0%s\0Y123456\0",'user@example.com','pa55word');
|
|
|
|
close(CPW);
|
|
|
|
|
|
|
|
my $status = $?;
|
|
|
|
print "FAIL\n" and exit if ( $status != 0 );
|
|
|
|
print "OK\n";
|
|
|
|
|
|
|
|
Save that script to vchkpw.pl and then run it as the same user that
|
|
|
|
qpsmtpd runs as:
|
|
|
|
|
|
|
|
setuidgid qpsmtpd perl vchkpw.pl
|
|
|
|
|
|
|
|
If you aren't using sudo, then remove $sudo from the open line.
|
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS
|
|
|
|
|
|
|
|
based upon authcheckpassword by Michael Holzt
|
|
|
|
and adapted by Johan Almqvist 2006-01-18
|
|
|
|
|
|
|
|
=head1 AUTHOR
|
|
|
|
|
|
|
|
Matt Simerson <msimerson@cpan.org>
|
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE
|
|
|
|
|
|
|
|
Copyright (c) 2010 Matt Simerson
|
|
|
|
|
|
|
|
This plugin is licensed under the same terms as the qpsmtpd package itself.
|
|
|
|
Please see the LICENSE file included with qpsmtpd for details.
|
|
|
|
|
|
|
|
=cut
|
|
|
|
|
|
|
|
sub register {
|
|
|
|
my ($self, $qp) = @_;
|
|
|
|
|
|
|
|
$self->register_hook("auth-plain", "auth_checkpassword");
|
|
|
|
$self->register_hook("auth-login", "auth_checkpassword");
|
|
|
|
}
|
|
|
|
|
|
|
|
sub auth_checkpassword {
|
|
|
|
my ($self, $transaction, $method, $user, $passClear, $passHash, $ticket) =
|
|
|
|
@_;
|
|
|
|
|
|
|
|
my $command = $self->qp->config("smtpauth-checkpassword")
|
|
|
|
or return (DECLINED);
|
|
|
|
my ($binary, $params) = $command =~ /^(\S+)(.*)$/;
|
|
|
|
|
|
|
|
return (DECLINED) if (!-x $binary);
|
|
|
|
my $sudo = get_sudo($binary);
|
|
|
|
|
|
|
|
open(CPW, "|$sudo $binary $params 3<&0");
|
|
|
|
printf(CPW "%s\0%s\0Y123456\0", $user, $passClear);
|
|
|
|
close(CPW);
|
|
|
|
|
|
|
|
my $status = $?;
|
|
|
|
|
|
|
|
return (DECLINED) if ($status != 0);
|
|
|
|
|
|
|
|
$self->connection->notes('authuser', $user);
|
|
|
|
return (OK, "auth_checkpassword");
|
|
|
|
}
|
|
|
|
|
|
|
|
sub get_sudo {
|
|
|
|
my $binary = shift;
|
|
|
|
|
|
|
|
return '' if $> == 0; # running as root
|
|
|
|
return '' if $> == 89 && $binary =~ /vchkpw/; # running as vpopmail
|
|
|
|
|
|
|
|
my $mode = (stat($binary))[2];
|
|
|
|
$mode = sprintf "%lo", $mode & 07777;
|
|
|
|
return '' if $mode eq '4711'; # $binary is setuid
|
|
|
|
|
|
|
|
my $sudo = `which sudo` || '/usr/local/bin/sudo';
|
|
|
|
return '' if !-x $sudo;
|
|
|
|
$sudo .= ' -C4'; # prevent sudo from clobber file descriptor 3
|
|
|
|
|
|
|
|
return "$sudo -u vpopmail" if $binary =~ /vchkpw/;
|
|
|
|
return $sudo;
|
|
|
|
}
|
|
|
|
|