#!perl -w =head1 NAME auth_flat_file - simple CRAM MD5 auth plugin using a flat password file =head1 SYNOPSIS in config/plugins: auth/auth_flat_file in config/flat_auth_pw username1:password1 username2:password2 ... =head1 DESCRIPTION This plugin implements a very simple authentication plugin using a flat password file containing username and password separated by colons. Note that this plugin enforces the use of a full email address (including @domain) as the username. There's no particular reason for this so feel free to modify the code to suit your setup. The password is stored on disk unencrypted, however authentication uses a HMAC algorithm so no password is transfered in the clear. =cut use strict; use warnings; use Qpsmtpd::Auth; use Qpsmtpd::Constants; sub register { my ($self, $qp) = @_; $self->register_hook('auth-plain', 'auth_flat_file'); $self->register_hook('auth-login', 'auth_flat_file'); $self->register_hook('auth-cram-md5', 'auth_flat_file'); } sub auth_flat_file { my ($self, $transaction, $method, $user, $passClear, $passHash, $ticket) = @_; if (!defined $passClear && !defined $passHash) { $self->log(LOGINFO, "fail: missing password"); return (DENY, "authflat - missing password"); } my ($pw_name, $pw_domain) = split /@/, lc($user); unless (defined $pw_domain) { $self->log(LOGINFO, "fail: missing domain"); return DECLINED; } my ($auth_line) = grep { /^$pw_name\@$pw_domain:/ } $self->qp->config('flat_auth_pw'); if (!defined $auth_line) { $self->log(LOGINFO, "fail: no such user: $user"); return DECLINED; } my ($auth_user, $auth_pass) = split(/:/, $auth_line, 2); # at this point we can assume the user name matched return Qpsmtpd::Auth::validate_password( $self, src_clear => $auth_pass, src_crypt => undef, attempt_clear => $passClear, attempt_hash => $passHash, method => $method, ticket => $ticket, deny => DENY, ); }