RM/ADD: removed old method added qpsmtpd smtp queueing module with encryption
This commit is contained in:
parent
adf73fcc7a
commit
0e9abcd26d
117
src/encrypt_gpg
117
src/encrypt_gpg
@ -1,117 +0,0 @@
|
||||
|
||||
=head1 NAME
|
||||
|
||||
encrypt_gpg - encrypt incoming emails whith the recipients PGP public key
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Plugin checks, if there is a trusted public key for each of the recipients
|
||||
of the incoming email, in the GnuPG public key ring of the user running qpsmtpd.
|
||||
If such a key exists the email is encrypted with these keys.
|
||||
|
||||
|
||||
=head1 PER USER CONFIG
|
||||
|
||||
The file encrypt_gpg_user is a lookup up table for eMails in the form:
|
||||
|
||||
email encryption_type
|
||||
|
||||
possible values for encryption_type are none and pgpmime. The standard is
|
||||
pgpmime. With none the encryption can be deactivated completely.
|
||||
|
||||
=cut
|
||||
|
||||
use Qpsmtpd::DSN;
|
||||
use Mail::GnuPG;
|
||||
use GnuPG::Interface;
|
||||
use MIME::Parser;
|
||||
|
||||
#init
|
||||
sub init {
|
||||
my ( $self, $qp, @args ) = @_;
|
||||
|
||||
|
||||
# get us the user config file
|
||||
my @encrypted_user_config = $self->qp->config("encrypt_gpg_user");
|
||||
my %user_hash;
|
||||
|
||||
for my $e (@encrypted_user_config) {
|
||||
my ( $email, $encryption_type ) = split /\s+/, $e, 2;
|
||||
$user_hash{$email}=$encryption_type;
|
||||
}
|
||||
|
||||
$self->{_gpg_user}=\%user_hash;
|
||||
|
||||
}
|
||||
|
||||
# search for the users public key
|
||||
# the key id can be given in a file or is search for on a keyserver
|
||||
# and create a Mail::GnuPG object
|
||||
sub hook_rcpt {
|
||||
my ( $self, $transaction, $recipient, %param ) = @_;
|
||||
my $rcpt = $recipient;
|
||||
$rcpt =~ s/<//;
|
||||
$rcpt =~ s/>//;
|
||||
|
||||
#get us the user hash
|
||||
my %user_hash = %{$self->{_gpg_user}};
|
||||
|
||||
if (defined($user_hash{$rcpt}) && $user_hash{$rcpt} eq "none" ) {
|
||||
$self->log( LOGINFO, "GPG: encryption deactivated for email " .$rcpt );
|
||||
$self->{_gpg_on}=0;
|
||||
return OK;
|
||||
}
|
||||
$self->{_gpg_on}=1;
|
||||
|
||||
my $gpg = new Mail::GnuPG( keydir => '/var/spool/qpsmtpd/.gnupg/', always_trust => 1 );
|
||||
|
||||
if ( !$gpg->has_public_key($rcpt) ) {
|
||||
$self->log( LOGINFO, "GPG: no key for -" . $rcpt . "- found !" );
|
||||
$self->{_gpg_on}=0;
|
||||
return OK;
|
||||
}
|
||||
|
||||
# save gnupg object for rest of the session
|
||||
$self->{_gpg} = $gpg;
|
||||
$self->{_gpg_recipient} = $rcpt;
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
#check if mail is already encrypted, otherwise encrypt it
|
||||
sub hook_data_post {
|
||||
my ( $self, $transaction ) = @_;
|
||||
|
||||
# if gpg is deactivated, skip this hook
|
||||
if ($self->{_gpg_on}==0) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
#parse queued message
|
||||
my $parser = new MIME::Parser();
|
||||
$parser->decode_bodies(1);
|
||||
$parser->output_to_core(1);
|
||||
my $mime = $parser->parse_open( $transaction->body_filename() );
|
||||
|
||||
#check if email is already encrypted
|
||||
if ( $self->{_gpg}->is_encrypted($mime) ) {
|
||||
$self->log( LOGINFO, "GPG: email already PGP encrypted" );
|
||||
return OK;
|
||||
}
|
||||
|
||||
#encrypt message
|
||||
my $code;
|
||||
$code = $self->{_gpg}->mime_encrypt( $mime, $self->{_gpg_recipient} );
|
||||
if ( $code != 0 ) {
|
||||
$self->log( LOGERROR, "GPG: " . $self->{_gpg}->{last_message}->[0] );
|
||||
return OK;
|
||||
}
|
||||
|
||||
# rewrite the queued message
|
||||
open my $queued_mail, ">" . $transaction->body_filename();
|
||||
print $queued_mail $mime->stringify;
|
||||
close $queued_mail;
|
||||
|
||||
return OK;
|
||||
}
|
129
src/queue_encrypt_gpg
Normal file
129
src/queue_encrypt_gpg
Normal file
@ -0,0 +1,129 @@
|
||||
use Qpsmtpd::DSN;
|
||||
use Mail::GnuPG;
|
||||
use MIME::Parser;
|
||||
use Net::SMTP;
|
||||
|
||||
#init
|
||||
sub init {
|
||||
my ( $self, $qp, @args ) = @_;
|
||||
|
||||
if ( @args > 0 ) {
|
||||
if ( $args[0] =~ /^([\.\w_-]+)$/ ) {
|
||||
$self->{_smtp_server} = $1;
|
||||
}
|
||||
else {
|
||||
die "Bad data in smtp server: $args[0]";
|
||||
}
|
||||
$self->{_smtp_port} = 25;
|
||||
if ( @args > 1 and $args[1] =~ /^(\d+)$/ ) {
|
||||
$self->{_smtp_port} = $1;
|
||||
}
|
||||
$self->log( LOGWARN, "WARNING: Ignoring additional arguments." ) if ( @args > 2 );
|
||||
}
|
||||
else {
|
||||
die("No SMTP server specified in smtp-forward config");
|
||||
}
|
||||
|
||||
# get us the user config file
|
||||
my @encrypted_user_config = $self->qp->config("encrypt_gpg_user");
|
||||
my %user_hash;
|
||||
|
||||
for my $e (@encrypted_user_config) {
|
||||
my ( $email, $encryption_type ) = split /\s+/, $e, 2;
|
||||
$user_hash{$email} = $encryption_type;
|
||||
}
|
||||
|
||||
$self->{_gpg_user} = \%user_hash;
|
||||
|
||||
}
|
||||
|
||||
# this subroutite returns the encrypted email, if a valid and trusted PGP Public Key is found
|
||||
# in the GnuPG keyring of the user running QPSMTPD for all the recipients of the eMail
|
||||
# if no key is found, the plain unencrypted eMail is returned
|
||||
sub encrypt_mail {
|
||||
my ( $self, $transaction ) = @_;
|
||||
|
||||
# set correct HOMEDIR and get us an GPG object
|
||||
$ENV{HOME} = ( getpwuid($>) )[7];
|
||||
my $gpg = new Mail::GnuPG( keydir => '/var/spool/qpsmtpd/.gnupg/', always_trust => 1 );
|
||||
|
||||
# get us all recipients and remove the brackets around them
|
||||
my @recipients_temp = $transaction->recipients();
|
||||
my @recipients;
|
||||
|
||||
for my $r (@recipients_temp) {
|
||||
$r =~ s/<//;
|
||||
$r =~ s/>//;
|
||||
push( @recipients, $r );
|
||||
}
|
||||
|
||||
# check if we have a trusted public key available for every recipient
|
||||
my $keys_available = 1;
|
||||
|
||||
for my $r (@recipients) {
|
||||
if ( !$gpg->has_public_key($r) ) {
|
||||
$self->log( LOGINFO, "GPG: no public key found for " . $r );
|
||||
$keys_available = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
#parse eMail into a Mime::Entity Object
|
||||
#
|
||||
|
||||
#enforce correct rights
|
||||
chmod 0600, $transaction->body_filename;
|
||||
|
||||
my $parser = new MIME::Parser();
|
||||
$parser->decode_bodies(1);
|
||||
$parser->output_to_core(1);
|
||||
my $mime = $parser->parse_open( $transaction->body_filename );
|
||||
|
||||
#if we have all keys available and eMail is not encrypted already
|
||||
if ( $keys_available == 1 && !$gpg->is_encrypted($mime) ) {
|
||||
|
||||
$self->log( LOGINFO, "GPG: encrypting email" );
|
||||
|
||||
#encrypt message
|
||||
my $code = $gpg->mime_encrypt( $mime, @recipients );
|
||||
if ( $code != 0 ) {
|
||||
$self->log( LOGERROR, "GPG: " . $self->{_gpg}->{last_message}->[0] );
|
||||
}
|
||||
|
||||
## Remove some headers which might have been broken by the process of encryption
|
||||
$mime->head()->delete($_) foreach qw( DKIM-Signature DomainKey-Signature );
|
||||
|
||||
}
|
||||
return $mime;
|
||||
}
|
||||
|
||||
sub hook_queue {
|
||||
my ( $self, $transaction ) = @_;
|
||||
|
||||
#encrypt email or not
|
||||
my $email = $self->encrypt_mail($transaction);
|
||||
|
||||
$self->log( LOGINFO, "forwarding to $self->{_smtp_server}:$self->{_smtp_port}" );
|
||||
|
||||
my $smtp = Net::SMTP->new(
|
||||
$self->{_smtp_server},
|
||||
Port => $self->{_smtp_port},
|
||||
Timeout => 60,
|
||||
Hello => $self->qp->config("me"),
|
||||
) || die $!;
|
||||
|
||||
$smtp->mail( $transaction->sender->address || "" )
|
||||
or return ( DECLINED, "Unable to queue message ($!)" );
|
||||
|
||||
for ( $transaction->recipients ) {
|
||||
$smtp->to( $_->address ) or return ( DECLINED, "Unable to queue message ($!)" );
|
||||
}
|
||||
|
||||
$smtp->data() or return ( DECLINED, "Unable to queue message ($!)" );
|
||||
|
||||
$smtp->datasend( $email->stringify );
|
||||
$smtp->dataend() or return ( DECLINED, "Unable to queue message ($!)" );
|
||||
$smtp->quit() or return ( DECLINED, "Unable to queue message ($!)" );
|
||||
$self->log( LOGINFO, "finished queueing" );
|
||||
return ( OK, "Queued!" );
|
||||
}
|
Loading…
Reference in New Issue
Block a user