[Rt-commit] r12075 - rt/branches/3.7-RTIR-RELENG/lib/RT/Crypt
ruz at bestpractical.com
ruz at bestpractical.com
Mon May 5 18:07:32 EDT 2008
Author: ruz
Date: Mon May 5 18:07:31 2008
New Revision: 12075
Modified:
rt/branches/3.7-RTIR-RELENG/lib/RT/Crypt/GnuPG.pm
Log:
* decrypt/verify inline GPG parts using blocks to avoid loosing of literals
Modified: rt/branches/3.7-RTIR-RELENG/lib/RT/Crypt/GnuPG.pm
==============================================================================
--- rt/branches/3.7-RTIR-RELENG/lib/RT/Crypt/GnuPG.pm (original)
+++ rt/branches/3.7-RTIR-RELENG/lib/RT/Crypt/GnuPG.pm Mon May 5 18:07:31 2008
@@ -1081,10 +1081,7 @@
return @res;
}
-sub VerifyInline {
- my %args = ( Data => undef, Top => undef, @_ );
- return DecryptInline( %args );
-}
+sub VerifyInline { return DecryptInline( @_ ) }
sub VerifyAttachment {
my %args = ( Data => undef, Signature => undef, Top => undef, @_ );
@@ -1286,7 +1283,7 @@
RT::EmailParser->_DecodeBody($args{'Data'});
}
- # handling passphrase in GnupGOptions
+ # handling passphrase in GnuPGOptions
$args{'Passphrase'} = delete $opt{'passphrase'}
if !defined($args{'Passphrase'});
@@ -1296,24 +1293,84 @@
my ($tmp_fh, $tmp_fn) = File::Temp::tempfile();
binmode $tmp_fh, ':raw';
+ my $io = $args{'Data'}->open('r');
+ unless ( $io ) {
+ die "Entity has no body, never should happen";
+ }
+
+ my ($had_literal, $in_block) = ('', 0);
+ my ($block_fh, $block_fn) = File::Temp::tempfile();
+ binmode $block_fh, ':raw';
+
+ my %res;
+ while ( defined(my $str = $io->getline) ) {
+ if ( $in_block && $str =~ /-----END PGP (?:MESSAGE|SIGNATURE)-----/ ) {
+ print $block_fh $str;
+ seek $block_fh, 0, 0;
+
+ my ($res_fh, $res_fn);
+ ($res_fh, $res_fn, %res) = _DecryptInlineBlock(
+ %args,
+ GnuPG => $gnupg,
+ BlockHandle => $block_fh,
+ );
+ return %res unless $res_fh;
+
+ print $tmp_fh "-----BEGIN OF PGP PROTECTED PART-----\n" if $had_literal;
+ while (my $buf = <$res_fh> ) {
+ print $tmp_fh $buf;
+ }
+ print $tmp_fh "-----END OF PART-----\n" if $had_literal;
+
+ ($block_fh, $block_fn) = File::Temp::tempfile();
+ binmode $block_fh, ':raw';
+ $in_block = 0;
+ }
+ elsif ( $in_block || $str =~ /-----BEGIN PGP (SIGNED )?MESSAGE-----/ ) {
+ $in_block = 1;
+ print $block_fh $str;
+ }
+ else {
+ print $tmp_fh $str;
+ $had_literal = 1 if /\S/s;
+ }
+ }
+ $io->close;
+
+ seek $tmp_fh, 0, 0;
+ $args{'Data'}->bodyhandle( new MIME::Body::File $tmp_fn );
+ $args{'Data'}->{'__store_tmp_handle_to_avoid_early_cleanup'} = $tmp_fh;
+ return %res;
+}
+
+sub _DecryptInlineBlock {
+ my %args = (
+ GnuPG => undef,
+ BlockHandle => undef,
+ Passphrase => undef,
+ @_
+ );
+ my $gnupg = $args{'GnuPG'};
+
+ my ($tmp_fh, $tmp_fn) = File::Temp::tempfile();
+ binmode $tmp_fh, ':raw';
+
my %handle;
my $handles = GnuPG::Handles->new(
- stdin => ($handle{'input'} = new IO::Handle),
+ stdin => $args{'BlockHandle'},
stdout => $tmp_fh,
stderr => ($handle{'error'} = new IO::Handle),
logger => ($handle{'logger'} = new IO::Handle),
status => ($handle{'status'} = new IO::Handle),
);
$handles->options( 'stdout' )->{'direct'} = 1;
+ $handles->options( 'stdin' )->{'direct'} = 1;
my %res;
eval {
local $SIG{'CHLD'} = 'DEFAULT';
$gnupg->passphrase( $args{'Passphrase'} );
my $pid = _safe_run_child { $gnupg->decrypt( handles => $handles ) };
- $args{'Data'}->bodyhandle->print( $handle{'input'} );
- close $handle{'input'};
-
waitpid $pid, 0;
};
$res{'exit_code'} = $?;
@@ -1332,14 +1389,12 @@
if ( $res{'status'} !~ /DECRYPTION_OKAY/ ) {
if ( $@ || $? ) {
$res{'message'} = $@? $@: "gpg exitted with error code ". ($? >> 8);
- return %res;
+ return (undef, undef, %res);
}
}
seek $tmp_fh, 0, 0;
- $args{'Data'}->bodyhandle( new MIME::Body::File $tmp_fn );
- $args{'Data'}->{'__store_tmp_handle_to_avoid_early_cleanup'} = $tmp_fh;
- return %res;
+ return ($tmp_fh, $tmp_fn, %res);
}
sub DecryptAttachment {
@@ -1349,8 +1404,41 @@
Passphrase => undef,
@_
);
- my %res = DecryptInline( %args );
- return %res if $res{'exit_code'};
+
+ my $gnupg = new GnuPG::Interface;
+ my %opt = RT->Config->Get('GnuPGOptions');
+ $opt{'digest-algo'} ||= 'SHA1';
+ $gnupg->options->hash_init(
+ _PrepareGnuPGOptions( %opt ),
+ meta_interactive => 0,
+ );
+
+ if ( $args{'Data'}->bodyhandle->is_encoded ) {
+ require RT::EmailParser;
+ RT::EmailParser->_DecodeBody($args{'Data'});
+ }
+
+ # handling passphrase in GnuPGOptions
+ $args{'Passphrase'} = delete $opt{'passphrase'}
+ if !defined($args{'Passphrase'});
+
+ $args{'Passphrase'} = GetPassphrase()
+ unless defined $args{'Passphrase'};
+
+ my ($tmp_fh, $tmp_fn) = File::Temp::tempfile();
+ binmode $tmp_fh, ':raw';
+ $args{'Data'}->bodyhandle->print( $tmp_fh );
+ seek $tmp_fh, 0, 0;
+
+ my ($res_fh, $res_fn, %res) = _DecryptInlineBlock(
+ %args,
+ GnuPG => $gnupg,
+ BlockHandle => $tmp_fh,
+ );
+ return %res unless $res_fh;
+
+ $args{'Data'}->bodyhandle( new MIME::Body::File $res_fn );
+ $args{'Data'}->{'__store_tmp_handle_to_avoid_early_cleanup'} = $res_fh;
my $filename = $args{'Data'}->head->recommended_filename;
$filename =~ s/\.pgp$//i;
More information about the Rt-commit
mailing list