New and improved! With POD! Includes usage notes and a perl script useful for 
diagnosing a checkpassword program.
---
MANIFEST                        |    1 +
plugins/auth/auth_checkpassword |  127 +++++++++++++++++++++++++++++++++++++++
2 files changed, 128 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..b7ed2ad
--- /dev/null
+++ b/plugins/auth/auth_checkpassword
@@ -0,0 +1,127 @@
+#!/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",'u...@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 <msimer...@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;
+}
+
+
+
-- 
1.7.0.6


Reply via email to