#!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, ); }