From fbbf43ad15c1025d9f1e0a2259371ff1533504cd Mon Sep 17 00:00:00 2001 From: Matt Simerson Date: Mon, 10 May 2010 19:07:48 -0400 Subject: added auth_checkpassword plugin New and improved! With POD! (because JP said so: http://www.nntp.perl.org/group/perl.qpsmtpd/2005/06/msg3145.html) Includes usage notes and a perl script useful for diagnosing a checkpassword program. Signed-off-by: Robert --- MANIFEST | 1 + plugins/auth/auth_checkpassword | 145 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 0 deletions(-) create mode 100644 plugins/auth/auth_checkpassword diff --git a/MANIFEST b/MANIFEST index 930ddbf..9d5912a 100644 --- a/MANIFEST +++ b/MANIFEST @@ -62,6 +62,7 @@ plugins/async/queue/smtp-forward plugins/async/require_resolvable_fromhost plugins/async/rhsbl plugins/async/uribl +plugins/auth/auth_checkpassword plugins/auth/auth_cvm_unix_local plugins/auth/auth_flat_file plugins/auth/auth_ldap_bind diff --git a/plugins/auth/auth_checkpassword b/plugins/auth/auth_checkpassword new file mode 100644 index 0000000..6337ff7 --- /dev/null +++ b/plugins/auth/auth_checkpassword @@ -0,0 +1,145 @@ +#!/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. + +=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 + +=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; +} + -- 1.7.2.2