| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 |
|
|---|
| 25 |
|
|---|
| 26 |
|
|---|
| 27 |
|
|---|
| 28 |
|
|---|
| 29 |
|
|---|
| 30 |
|
|---|
| 31 |
|
|---|
| 32 |
|
|---|
| 33 |
|
|---|
| 34 |
use lib '/usr/lib/gpgdir'; |
|---|
| 35 |
use File::Find; |
|---|
| 36 |
use File::Copy; |
|---|
| 37 |
use Term::ReadKey; |
|---|
| 38 |
use GnuPG::Interface; |
|---|
| 39 |
use IO::File; |
|---|
| 40 |
use IO::Handle; |
|---|
| 41 |
use Getopt::Long; |
|---|
| 42 |
use Cwd; |
|---|
| 43 |
use strict; |
|---|
| 44 |
|
|---|
| 45 |
|
|---|
| 46 |
my $version = '1.8'; |
|---|
| 47 |
my $revision_svn = '$Revision$'; |
|---|
| 48 |
my $rev_num = '1'; |
|---|
| 49 |
($rev_num) = $revision_svn =~ m|\$Rev.*:\s+(\S+)|; |
|---|
| 50 |
|
|---|
| 51 |
|
|---|
| 52 |
my $encrypt_user = ''; |
|---|
| 53 |
my $gpg_homedir = ''; |
|---|
| 54 |
my $dir = ''; |
|---|
| 55 |
my $pw = ''; |
|---|
| 56 |
my $encrypt_dir = ''; |
|---|
| 57 |
my $decrypt_dir = ''; |
|---|
| 58 |
my $homedir = ''; |
|---|
| 59 |
my $exclude_pat = ''; |
|---|
| 60 |
my $exclude_file = ''; |
|---|
| 61 |
my $include_pat = ''; |
|---|
| 62 |
my $include_file = ''; |
|---|
| 63 |
my $total_encrypted = 0; |
|---|
| 64 |
my $total_decrypted = 0; |
|---|
| 65 |
my $norecurse = 0; |
|---|
| 66 |
my $printver = 0; |
|---|
| 67 |
my $no_delete = 0; |
|---|
| 68 |
my $no_fs_times = 0; |
|---|
| 69 |
my $test_and_exit = 0; |
|---|
| 70 |
my $trial_run = 0; |
|---|
| 71 |
my $skip_test_mode = 0; |
|---|
| 72 |
my $verbose = 0; |
|---|
| 73 |
my $quiet = 0; |
|---|
| 74 |
my $use_gpg_agent = 0; |
|---|
| 75 |
my $gpg_agent_info = ''; |
|---|
| 76 |
my $force_mode = 0; |
|---|
| 77 |
my $help = 0; |
|---|
| 78 |
my $wipe_mode = 0; |
|---|
| 79 |
my $encrypt_mode = 0; |
|---|
| 80 |
my $use_default_key = 0; |
|---|
| 81 |
my $pw_file = ''; |
|---|
| 82 |
my $wipe_cmd = '/usr/bin/wipe'; |
|---|
| 83 |
my $wipe_cmdline = ''; |
|---|
| 84 |
my $wipe_interactive = 0; |
|---|
| 85 |
my $interactive_mode = 0; |
|---|
| 86 |
my $ascii_armor_mode = 0; |
|---|
| 87 |
my @exclude_patterns = (); |
|---|
| 88 |
my @include_patterns = (); |
|---|
| 89 |
my %files = (); |
|---|
| 90 |
my %options = (); |
|---|
| 91 |
my %obfuscate_ctrs = (); |
|---|
| 92 |
my %obfuscated_dirs = (); |
|---|
| 93 |
my $total_mapped_files = 0; |
|---|
| 94 |
my $have_obfuscated_file = 0; |
|---|
| 95 |
my $cmdline_no_password = 0; |
|---|
| 96 |
my $obfuscate_mode = 0; |
|---|
| 97 |
my $obfuscate_map_filename = '.gpgdir_map_file'; |
|---|
| 98 |
my $overwrite_encrypted = 0; |
|---|
| 99 |
my $overwrite_decrypted = 0; |
|---|
| 100 |
my $symmetric_mode = 0; |
|---|
| 101 |
my $DEL_SOURCE_FILE = 1; |
|---|
| 102 |
my $NO_DEL_SOURCE_FILE = 0; |
|---|
| 103 |
|
|---|
| 104 |
|
|---|
| 105 |
my $ACCEPT_YES_DEFAULT = 1; |
|---|
| 106 |
my $ACCEPT_NO_DEFAULT = 2; |
|---|
| 107 |
|
|---|
| 108 |
unless ($< == $>) { |
|---|
| 109 |
die "[*] Real and effective uid must be the same. Make sure\n", |
|---|
| 110 |
" gpgdir has not been installed as a SUID binary.\n", |
|---|
| 111 |
"Exiting."; |
|---|
| 112 |
} |
|---|
| 113 |
|
|---|
| 114 |
my @args_cp = @ARGV; |
|---|
| 115 |
|
|---|
| 116 |
|
|---|
| 117 |
Getopt::Long::Configure('no_ignore_case'); |
|---|
| 118 |
|
|---|
| 119 |
die "[-] Use --help for usage information.\n" unless(GetOptions ( |
|---|
| 120 |
'encrypt=s' => \$encrypt_dir, |
|---|
| 121 |
'decrypt=s' => \$decrypt_dir, |
|---|
| 122 |
'gnupg-dir=s' => \$gpg_homedir, |
|---|
| 123 |
'pw-file=s' => \$pw_file, |
|---|
| 124 |
'agent' => \$use_gpg_agent, |
|---|
| 125 |
'Agent-info=s' => \$gpg_agent_info, |
|---|
| 126 |
|
|---|
| 127 |
'Wipe' => \$wipe_mode, |
|---|
| 128 |
'wipe-path=s' => \$wipe_cmd, |
|---|
| 129 |
'wipe-interactive' => \$wipe_interactive, |
|---|
| 130 |
'wipe-cmdline=s' => \$wipe_cmdline, |
|---|
| 131 |
'Obfuscate-filenames' => \$obfuscate_mode, |
|---|
| 132 |
|
|---|
| 133 |
'obfuscate-map-file=s' => \$obfuscate_map_filename, |
|---|
| 134 |
'Force' => \$force_mode, |
|---|
| 135 |
'overwrite-encrypted' => \$overwrite_encrypted, |
|---|
| 136 |
|
|---|
| 137 |
'overwrite-decrypted' => \$overwrite_decrypted, |
|---|
| 138 |
|
|---|
| 139 |
'Exclude=s' => \$exclude_pat, |
|---|
| 140 |
|
|---|
| 141 |
'Exclude-from=s' => \$exclude_file, |
|---|
| 142 |
|
|---|
| 143 |
'Include=s' => \$include_pat, |
|---|
| 144 |
|
|---|
| 145 |
'Include-from=s' => \$include_file, |
|---|
| 146 |
|
|---|
| 147 |
|
|---|
| 148 |
'test-mode' => \$test_and_exit, |
|---|
| 149 |
|
|---|
| 150 |
'Trial-run' => \$trial_run, |
|---|
| 151 |
|
|---|
| 152 |
'quiet' => \$quiet, |
|---|
| 153 |
|
|---|
| 154 |
'Interactive' => \$interactive_mode, |
|---|
| 155 |
|
|---|
| 156 |
'Key-id=s' => \$encrypt_user, |
|---|
| 157 |
'Default-key' => \$use_default_key, |
|---|
| 158 |
|
|---|
| 159 |
'Symmetric' => \$symmetric_mode, |
|---|
| 160 |
|
|---|
| 161 |
|
|---|
| 162 |
|
|---|
| 163 |
'Plain-ascii' => \$ascii_armor_mode, |
|---|
| 164 |
|
|---|
| 165 |
'skip-test' => \$skip_test_mode, |
|---|
| 166 |
'no-recurse' => \$norecurse, |
|---|
| 167 |
|
|---|
| 168 |
'no-delete' => \$no_delete, |
|---|
| 169 |
|
|---|
| 170 |
'no-password' => \$cmdline_no_password, |
|---|
| 171 |
|
|---|
| 172 |
|
|---|
| 173 |
'user-homedir=s' => \$homedir, |
|---|
| 174 |
'no-preserve-times' => \$no_fs_times, |
|---|
| 175 |
'verbose' => \$verbose, |
|---|
| 176 |
'Version' => \$printver, |
|---|
| 177 |
'help' => \$help |
|---|
| 178 |
)); |
|---|
| 179 |
&usage_and_exit() if $help; |
|---|
| 180 |
|
|---|
| 181 |
print "[+] gpgdir v$version (file revision: $rev_num)\n", |
|---|
| 182 |
" by Michael Rash <mbr\@cipherdyne.org>\n" |
|---|
| 183 |
and exit 0 if $printver; |
|---|
| 184 |
|
|---|
| 185 |
if ($symmetric_mode and ($use_gpg_agent or $gpg_agent_info)) { |
|---|
| 186 |
die "[*] gpg-agent incompatible with --Symmetric mode"; |
|---|
| 187 |
} |
|---|
| 188 |
|
|---|
| 189 |
if ($encrypt_dir and $overwrite_decrypted) { |
|---|
| 190 |
die "[*] The -e and --overwrite-decrypted options are incompatible."; |
|---|
| 191 |
} |
|---|
| 192 |
if ($decrypt_dir and $overwrite_encrypted) { |
|---|
| 193 |
die "[*] The -d and --overwrite-encrypted options are incompatible."; |
|---|
| 194 |
} |
|---|
| 195 |
|
|---|
| 196 |
if ($wipe_mode) { |
|---|
| 197 |
unless (-e $wipe_cmd) { |
|---|
| 198 |
die "[*] Can't find wipe command at: $wipe_cmd,\n", |
|---|
| 199 |
" use --wipe-path to specify path."; |
|---|
| 200 |
} |
|---|
| 201 |
unless (-e $wipe_cmd) { |
|---|
| 202 |
die "[*] Can't execute $wipe_cmd"; |
|---|
| 203 |
} |
|---|
| 204 |
} |
|---|
| 205 |
|
|---|
| 206 |
my $initial_dir = cwd or die "[*] Could not get CWD: $!"; |
|---|
| 207 |
|
|---|
| 208 |
if ($gpg_homedir) { |
|---|
| 209 |
|
|---|
| 210 |
if ($gpg_homedir !~ m|^/|) { |
|---|
| 211 |
$gpg_homedir = $initial_dir . '/' . $gpg_homedir; |
|---|
| 212 |
} |
|---|
| 213 |
} |
|---|
| 214 |
|
|---|
| 215 |
|
|---|
| 216 |
if ($verbose) { |
|---|
| 217 |
%options = ('homedir' => $gpg_homedir); |
|---|
| 218 |
} else { |
|---|
| 219 |
%options = ( |
|---|
| 220 |
'batch' => 1, |
|---|
| 221 |
'homedir' => $gpg_homedir |
|---|
| 222 |
); |
|---|
| 223 |
} |
|---|
| 224 |
|
|---|
| 225 |
$options{'armor'} = 1 if $ascii_armor_mode; |
|---|
| 226 |
|
|---|
| 227 |
|
|---|
| 228 |
$homedir = &get_homedir() unless $homedir; |
|---|
| 229 |
|
|---|
| 230 |
unless ($symmetric_mode) { |
|---|
| 231 |
unless ($gpg_homedir) { |
|---|
| 232 |
$gpg_homedir = "${homedir}/.gnupg" |
|---|
| 233 |
if -d "${homedir}/.gnupg"; |
|---|
| 234 |
} |
|---|
| 235 |
unless (-d $gpg_homedir) { |
|---|
| 236 |
die "[*] GnuPG directory: $gpg_homedir does not exist. Please\n", |
|---|
| 237 |
" create it by executing: \"gpg --gen-key\". Exiting.\n"; |
|---|
| 238 |
} |
|---|
| 239 |
|
|---|
| 240 |
|
|---|
| 241 |
$encrypt_user = &get_key() unless $encrypt_user or $use_default_key; |
|---|
| 242 |
} |
|---|
| 243 |
|
|---|
| 244 |
if ($decrypt_dir and $encrypt_dir) { |
|---|
| 245 |
die "[*] You cannot encrypt and decrypt the same directory, see --help\n"; |
|---|
| 246 |
} |
|---|
| 247 |
|
|---|
| 248 |
unless ($decrypt_dir or $encrypt_dir or $test_and_exit) { |
|---|
| 249 |
print "[*] Please specify -e <dir>, -d <dir>, or --test-mode, see --help\n"; |
|---|
| 250 |
} |
|---|
| 251 |
|
|---|
| 252 |
|
|---|
| 253 |
push @exclude_patterns, $exclude_pat if $exclude_pat; |
|---|
| 254 |
|
|---|
| 255 |
if ($exclude_file) { |
|---|
| 256 |
open P, "< $exclude_file" or die "[*] Could not open file: $exclude_file"; |
|---|
| 257 |
my @lines = <P>; |
|---|
| 258 |
close P; |
|---|
| 259 |
for my $line (@lines) { |
|---|
| 260 |
next unless $line =~ /\S/; |
|---|
| 261 |
chomp $line; |
|---|
| 262 |
push @exclude_patterns, qr{$line}; |
|---|
| 263 |
} |
|---|
| 264 |
} |
|---|
| 265 |
|
|---|
| 266 |
|
|---|
| 267 |
push @include_patterns, $include_pat if $include_pat; |
|---|
| 268 |
|
|---|
| 269 |
if ($include_file) { |
|---|
| 270 |
open P, "< $include_file" or die "[*] Could not open file: $include_file"; |
|---|
| 271 |
my @lines = <P>; |
|---|
| 272 |
close P; |
|---|
| 273 |
for my $line (@lines) { |
|---|
| 274 |
next unless $line =~ /\S/; |
|---|
| 275 |
chomp $line; |
|---|
| 276 |
push @include_patterns, qr{$line}; |
|---|
| 277 |
} |
|---|
| 278 |
} |
|---|
| 279 |
|
|---|
| 280 |
if ($encrypt_dir) { |
|---|
| 281 |
$dir = $encrypt_dir; |
|---|
| 282 |
$encrypt_mode = 1; |
|---|
| 283 |
} elsif ($decrypt_dir) { |
|---|
| 284 |
$dir = $decrypt_dir; |
|---|
| 285 |
$encrypt_mode = 0; |
|---|
| 286 |
} |
|---|
| 287 |
|
|---|
| 288 |
if ($dir) { |
|---|
| 289 |
die "[*] Directory does not exist: $dir" unless -e $dir; |
|---|
| 290 |
die "[*] Not a directory: $dir" unless -d $dir; |
|---|
| 291 |
} |
|---|
| 292 |
|
|---|
| 293 |
|
|---|
| 294 |
|
|---|
| 295 |
$skip_test_mode = 1 if $trial_run; |
|---|
| 296 |
|
|---|
| 297 |
if ($symmetric_mode) { |
|---|
| 298 |
&get_password(); |
|---|
| 299 |
} else { |
|---|
| 300 |
&get_password() unless $encrypt_mode and $skip_test_mode; |
|---|
| 301 |
} |
|---|
| 302 |
|
|---|
| 303 |
if ($dir eq '.') { |
|---|
| 304 |
$dir = $initial_dir; |
|---|
| 305 |
} elsif ($dir !~ m|^/|) { |
|---|
| 306 |
$dir = $initial_dir . '/' . $dir; |
|---|
| 307 |
} |
|---|
| 308 |
$dir =~ s|/$||; |
|---|
| 309 |
|
|---|
| 310 |
|
|---|
| 311 |
unless ($skip_test_mode) { |
|---|
| 312 |
my $rv = &test_mode(); |
|---|
| 313 |
exit $rv if $test_and_exit; |
|---|
| 314 |
} |
|---|
| 315 |
|
|---|
| 316 |
if ($encrypt_mode) { |
|---|
| 317 |
print "[+] Encrypting directory: $dir\n" unless $quiet; |
|---|
| 318 |
} else { |
|---|
| 319 |
print "[+] Decrypting directory: $dir\n" unless $quiet; |
|---|
| 320 |
} |
|---|
| 321 |
|
|---|
| 322 |
|
|---|
| 323 |
&get_files($dir); |
|---|
| 324 |
|
|---|
| 325 |
|
|---|
| 326 |
&gpg_operation(); |
|---|
| 327 |
|
|---|
| 328 |
&obfuscated_mapping_files() if $obfuscate_mode; |
|---|
| 329 |
|
|---|
| 330 |
unless ($obfuscate_mode) { |
|---|
| 331 |
if ($have_obfuscated_file) { |
|---|
| 332 |
print "[-] Obfuscated filenames detected, try decrypting with -O.\n" |
|---|
| 333 |
unless $quiet; |
|---|
| 334 |
} |
|---|
| 335 |
} |
|---|
| 336 |
|
|---|
| 337 |
if ($encrypt_mode) { |
|---|
| 338 |
print "[+] Total number of files encrypted: " . |
|---|
| 339 |
"$total_encrypted\n" unless $quiet; |
|---|
| 340 |
} else { |
|---|
| 341 |
print "[+] Total number of files decrypted: " . |
|---|
| 342 |
"$total_decrypted\n" unless $quiet; |
|---|
| 343 |
} |
|---|
| 344 |
|
|---|
| 345 |
exit 0; |
|---|
| 346 |
|
|---|
| 347 |
|
|---|
| 348 |
sub encrypt_file() { |
|---|
| 349 |
my ($in_file, $out_file, $del_flag) = @_; |
|---|
| 350 |
|
|---|
| 351 |
my $gpg = GnuPG::Interface->new(); |
|---|
| 352 |
$gpg->options->hash_init(%options); |
|---|
| 353 |
|
|---|
| 354 |
die "[*] Could not create new gpg object with ", |
|---|
| 355 |
"homedir: $gpg_homedir" unless $gpg; |
|---|
| 356 |
|
|---|
| 357 |
unless ($symmetric_mode or $use_default_key) { |
|---|
| 358 |
$gpg->options->default_key($encrypt_user); |
|---|
| 359 |
$gpg->options->push_recipients($encrypt_user); |
|---|
| 360 |
} |
|---|
| 361 |
|
|---|
| 362 |
my ($input_fh, $output_fh, $error_fh, $pw_fh, $status_fh) = |
|---|
| 363 |
(IO::File->new($in_file), |
|---|
| 364 |
IO::File->new("> $out_file"), |
|---|
| 365 |
IO::Handle->new(), |
|---|
| 366 |
IO::Handle->new(), |
|---|
| 367 |
IO::Handle->new()); |
|---|
| 368 |
|
|---|
| 369 |
my $handles = GnuPG::Handles->new( |
|---|
| 370 |
stdin => $input_fh, |
|---|
| 371 |
stdout => $output_fh, |
|---|
| 372 |
stderr => $error_fh, |
|---|
| 373 |
passphrase => $pw_fh, |
|---|
| 374 |
status => $status_fh |
|---|
| 375 |
); |
|---|
| 376 |
$handles->options('stdin')->{'direct'} = 1; |
|---|
| 377 |
$handles->options('stdout')->{'direct'} = 1; |
|---|
| 378 |
|
|---|
| 379 |
my $pid; |
|---|
| 380 |
|
|---|
| 381 |
if ($use_gpg_agent or $gpg_agent_info) { |
|---|
| 382 |
|
|---|
| 383 |
|
|---|
| 384 |
if ($gpg_agent_info) { |
|---|
| 385 |
$ENV{'GPG_AGENT_INFO'} = $gpg_agent_info; |
|---|
| 386 |
} |
|---|
| 387 |
|
|---|
| 388 |
$pid = $gpg->encrypt('handles' => $handles, |
|---|
| 389 |
'command_args' => [ qw( --use-agent ) ]); |
|---|
| 390 |
|
|---|
| 391 |
} else { |
|---|
| 392 |
if ($symmetric_mode) { |
|---|
| 393 |
$pid = $gpg->encrypt_symmetrically('handles' => $handles); |
|---|
| 394 |
} else { |
|---|
| 395 |
$pid = $gpg->encrypt('handles' => $handles); |
|---|
| 396 |
} |
|---|
| 397 |
} |
|---|
| 398 |
|
|---|
| 399 |
print $pw_fh $pw; |
|---|
| 400 |
close $pw_fh; |
|---|
| 401 |
|
|---|
| 402 |
my @errors = <$error_fh>; |
|---|
| 403 |
|
|---|
| 404 |
if ($verbose) { |
|---|
| 405 |
print for @errors; |
|---|
| 406 |
} else { |
|---|
| 407 |
for (@errors) { |
|---|
| 408 |
print if /bad\s+pass/; |
|---|
| 409 |
} |
|---|
| 410 |
} |
|---|
| 411 |
|
|---|
| 412 |
close $input_fh; |
|---|
| 413 |
close $output_fh; |
|---|
| 414 |
close $error_fh; |
|---|
| 415 |
close $status_fh; |
|---|
| 416 |
|
|---|
| 417 |
waitpid $pid, 0; |
|---|
| 418 |
|
|---|
| 419 |
if (-s $out_file == 0) { |
|---|
| 420 |
&delete_file($out_file); |
|---|
| 421 |
&delete_file($in_file) if $del_flag == $DEL_SOURCE_FILE; |
|---|
| 422 |
if ($use_gpg_agent) { |
|---|
| 423 |
die "[*] Created zero-size file: $out_file\n", |
|---|
| 424 |
" Maybe gpg-agent does not yet have the password for that key?\n", |
|---|
| 425 |
" Try re-running with -v."; |
|---|
| 426 |
} else { |
|---|
| 427 |
die "[*] Created zero-size file: $out_file\n", |
|---|
| 428 |
" Bad password? Try re-running with -v."; |
|---|
| 429 |
} |
|---|
| 430 |
} |
|---|
| 431 |
|
|---|
| 432 |
return; |
|---|
| 433 |
} |
|---|
| 434 |
|
|---|
| 435 |
sub decrypt_file() { |
|---|
| 436 |
my ($in_file, $out_file, $del_flag) = @_; |
|---|
| 437 |
|
|---|
| 438 |
my $gpg = GnuPG::Interface->new(); |
|---|
| 439 |
$gpg->options->hash_init(%options); |
|---|
| 440 |
|
|---|
| 441 |
die "[*] Could not create new gpg object with ", |
|---|
| 442 |
"homedir: $gpg_homedir" unless $gpg; |
|---|
| 443 |
|
|---|
| 444 |
unless ($symmetric_mode or $use_default_key) { |
|---|
| 445 |
$gpg->options->default_key($encrypt_user); |
|---|
| 446 |
$gpg->options->push_recipients($encrypt_user); |
|---|
| 447 |
} |
|---|
| 448 |
|
|---|
| 449 |
my ($input_fh, $output_fh, $error_fh, $pw_fh, $status_fh) = |
|---|
| 450 |
(IO::File->new($in_file), |
|---|
| 451 |
IO::File->new("> $out_file"), |
|---|
| 452 |
IO::Handle->new(), |
|---|
| 453 |
IO::Handle->new(), |
|---|
| 454 |
IO::Handle->new()); |
|---|
| 455 |
|
|---|
| 456 |
my $handles = GnuPG::Handles->new( |
|---|
| 457 |
stdin => $input_fh, |
|---|
| 458 |
stdout => $output_fh, |
|---|
| 459 |
stderr => $error_fh, |
|---|
| 460 |
passphrase => $pw_fh, |
|---|
| 461 |
status => $status_fh |
|---|
| 462 |
); |
|---|
| 463 |
$handles->options('stdin')->{'direct'} = 1; |
|---|
| 464 |
$handles->options('stdout')->{'direct'} = 1; |
|---|
| 465 |
|
|---|
| 466 |
my $pid; |
|---|
| 467 |
|
|---|
| 468 |
if ($use_gpg_agent) { |
|---|
| 469 |
$pid = $gpg->decrypt('handles' => $handles, |
|---|
| 470 |
'command_args' => [ qw( --use-agent ) ]); |
|---|
| 471 |
} else { |
|---|
| 472 |
$pid = $gpg->decrypt('handles' => $handles); |
|---|
| 473 |
} |
|---|
| 474 |
|
|---|
| 475 |
print $pw_fh $pw; |
|---|
| 476 |
close $pw_fh; |
|---|
| 477 |
|
|---|
| 478 |
my @errors = <$error_fh>; |
|---|
| 479 |
|
|---|
| 480 |
if ($verbose) { |
|---|
| 481 |
print for @errors; |
|---|
| 482 |
} else { |
|---|
| 483 |
for (@errors) { |
|---|
| 484 |
print if /bad\s+pass/; |
|---|
| 485 |
} |
|---|
| 486 |
} |
|---|
| 487 |
|
|---|
| 488 |
close $input_fh; |
|---|
| 489 |
close $output_fh; |
|---|
| 490 |
close $error_fh; |
|---|
| 491 |
close $status_fh; |
|---|
| 492 |
|
|---|
| 493 |
waitpid $pid, 0; |
|---|
| 494 |
|
|---|
| 495 |
if (-s $out_file == 0) { |
|---|
| 496 |
&delete_file($out_file); |
|---|
| 497 |
&delete_file($in_file) if $del_flag == $DEL_SOURCE_FILE; |
|---|
| 498 |
if ($use_gpg_agent) { |
|---|
| 499 |
die "[*] Created zero-size file: $out_file\n", |
|---|
| 500 |
" Maybe gpg-agent does not yet have the password for that key?\n", |
|---|
| 501 |
" Try re-running with -v."; |
|---|
| 502 |
} else { |
|---|
| 503 |
die "[*] Created zero-size file: $out_file\n", |
|---|
| 504 |
" Bad password? Try re-running with -v."; |
|---|
| 505 |
} |
|---|
| 506 |
} |
|---|
| 507 |
return; |
|---|
| 508 |
} |
|---|
| 509 |
|
|---|
| 510 |
sub delete_file() { |
|---|
| 511 |
my $file = shift; |
|---|
| 512 |
|
|---|
| 513 |
return if $no_delete; |
|---|
| 514 |
return unless -e $file; |
|---|
| 515 |
|
|---|
| 516 |
if ($wipe_mode) { |
|---|
| 517 |
my $cmd = $wipe_cmd; |
|---|
| 518 |
if ($wipe_cmdline) { |
|---|
| 519 |
$cmd .= " $wipe_cmdline "; |
|---|
| 520 |
} else { |
|---|
| 521 |
if ($wipe_interactive) { |
|---|
| 522 |
$cmd .= ' -i '; |
|---|
| 523 |
} else { |
|---|
| 524 |
$cmd .= ' -I -s '; |
|---|
| 525 |
} |
|---|
| 526 |
} |
|---|
| 527 |
$cmd .= $file; |
|---|
| 528 |
if ($verbose) { |
|---|
| 529 |
print " Executing: $cmd\n"; |
|---|
| 530 |
} |
|---|
| 531 |
|
|---|
| 532 |
|
|---|
| 533 |
system $cmd; |
|---|
| 534 |
|
|---|
| 535 |
} else { |
|---|
| 536 |
unlink $file; |
|---|
| 537 |
} |
|---|
| 538 |
|
|---|
| 539 |
if (-e $file) { |
|---|
| 540 |
my $msg = "[-] Could not delete file: $file\n"; |
|---|
| 541 |
if ($force_mode) { |
|---|
| 542 |
print $msg unless $quiet; |
|---|
| 543 |
} else { |
|---|
| 544 |
die $msg unless $quiet; |
|---|
| 545 |
} |
|---|
| 546 |
} |
|---|
| 547 |
return; |
|---|
| 548 |
} |
|---|
| 549 |
|
|---|
| 550 |
sub gpg_operation() { |
|---|
| 551 |
|
|---|
| 552 |
|
|---|
| 553 |
FILE: for my $file (sort |
|---|
| 554 |
{$files{$a}{'mtime'} <=> $files{$b}{'mtime'}} keys %files) { |
|---|
| 555 |
|
|---|
| 556 |
|
|---|
| 557 |
|
|---|
| 558 |
if (@exclude_patterns and &exclude_file($file)) { |
|---|
| 559 |
print "[+] Skipping excluded file: $file\n" |
|---|
| 560 |
if $verbose and not $quiet; |
|---|
| 561 |
next FILE; |
|---|
| 562 |
} |
|---|
| 563 |
|
|---|
| 564 |
|
|---|
| 565 |
|
|---|
| 566 |
if (@include_patterns and not &include_file($file)) { |
|---|
| 567 |
print "[+] Skipping non-included file: $file\n" |
|---|
| 568 |
if $verbose and not $quiet; |
|---|
| 569 |
next FILE; |
|---|
| 570 |
} |
|---|
| 571 |
|
|---|
| 572 |
|
|---|
| 573 |
my ($dir, $filename) = ($file =~ m|(.*)/(.*)|); |
|---|
| 574 |
|
|---|
| 575 |
unless (chdir($dir)) { |
|---|
| 576 |
print "[-] Could not chdir $dir, skipping.\n" unless $quiet; |
|---|
| 577 |
next FILE; |
|---|
| 578 |
} |
|---|
| 579 |
|
|---|
| 580 |
my $mtime = $files{$file}{'mtime'}; |
|---|
| 581 |
my $atime = $files{$file}{'atime'}; |
|---|
| 582 |
|
|---|
| 583 |
if ($encrypt_mode) { |
|---|
| 584 |
|
|---|
| 585 |
my $encrypt_filename = "$filename.gpg"; |
|---|
| 586 |
|
|---|
| 587 |
if ($obfuscate_mode) { |
|---|
| 588 |
|
|---|
| 589 |
unless (defined $obfuscate_ctrs{$dir}) { |
|---|
| 590 |
|
|---|
| 591 |
|
|---|
| 592 |
|
|---|
| 593 |
|
|---|
| 594 |
&handle_old_obfuscated_map_file(); |
|---|
| 595 |
|
|---|
| 596 |
|
|---|
| 597 |
|
|---|
| 598 |
$obfuscate_ctrs{$dir} = 1; |
|---|
| 599 |
} |
|---|
| 600 |
|
|---|
| 601 |
$encrypt_filename = 'gpgdir_' . $$ . '_' |
|---|
| 602 |
. $obfuscate_ctrs{$dir} . '.gpg'; |
|---|
| 603 |
} |
|---|
| 604 |
|
|---|
| 605 |
if ($ascii_armor_mode) { |
|---|
| 606 |
$encrypt_filename = "$filename.asc"; |
|---|
| 607 |
} |
|---|
| 608 |
|
|---|
| 609 |
if (-e $encrypt_filename and not $overwrite_encrypted) { |
|---|
| 610 |
print "[-] Encrypted file $dir/$encrypt_filename already ", |
|---|
| 611 |
"exists, skipping.\n" unless $quiet; |
|---|
| 612 |
next FILE; |
|---|
| 613 |
} |
|---|
| 614 |
|
|---|
| 615 |
if ($interactive_mode) { |
|---|
| 616 |
next FILE unless (&query_yes_no( |
|---|
| 617 |
" Encrypt: $file ([y]/n)? ", $ACCEPT_YES_DEFAULT)); |
|---|
| 618 |
} |
|---|
| 619 |
|
|---|
| 620 |
print "[+] Encrypting: $file\n" unless $quiet; |
|---|
| 621 |
|
|---|
| 622 |
unless ($trial_run) { |
|---|
| 623 |
|
|---|
| 624 |
&encrypt_file($filename, $encrypt_filename, |
|---|
| 625 |
$NO_DEL_SOURCE_FILE); |
|---|
| 626 |
|
|---|
| 627 |
if (-e $encrypt_filename && -s $encrypt_filename != 0) { |
|---|
| 628 |
|
|---|
| 629 |
|
|---|
| 630 |
unless ($no_fs_times) { |
|---|
| 631 |
if (defined $mtime and $mtime and |
|---|
| 632 |
defined $atime and $atime) { |
|---|
| 633 |
utime $atime, $mtime, $encrypt_filename; |
|---|
| 634 |
} |
|---|
| 635 |
} |
|---|
| 636 |
|
|---|
| 637 |
|
|---|
| 638 |
if ($wipe_mode and not $quiet) { |
|---|
| 639 |
print " Securely deleting file: $file\n"; |
|---|
| 640 |
} |
|---|
| 641 |
&delete_file($filename); |
|---|
| 642 |
|
|---|
| 643 |
if ($obfuscate_mode) { |
|---|
| 644 |
|
|---|
| 645 |
|
|---|
| 646 |
&append_obfuscated_mapping($filename, |
|---|
| 647 |
$encrypt_filename); |
|---|
| 648 |
|
|---|
| 649 |
$obfuscate_ctrs{$dir}++; |
|---|
| 650 |
} |
|---|
| 651 |
|
|---|
| 652 |
$total_encrypted++; |
|---|
| 653 |
|
|---|
| 654 |
} else { |
|---|
| 655 |
print "[-] Could not encrypt file: $file\n" unless $quiet; |
|---|
| 656 |
next FILE; |
|---|
| 657 |
} |
|---|
| 658 |
} |
|---|
| 659 |
|
|---|
| 660 |
} else { |
|---|
| 661 |
|
|---|
| 662 |
|
|---|
| 663 |
my $decrypt_filename = ''; |
|---|
| 664 |
if ($filename =~ /^(.+)\.gpg$/) { |
|---|
| 665 |
$decrypt_filename = $1; |
|---|
| 666 |
} elsif ($filename =~ /^(.+)\.asc$/) { |
|---|
| 667 |
$decrypt_filename = $1; |
|---|
| 668 |
} |
|---|
| 669 |
|
|---|
| 670 |
if ($obfuscate_mode) { |
|---|
| 671 |
|
|---|
| 672 |
&import_obfuscated_file_map($dir) |
|---|
| 673 |
unless defined $obfuscated_dirs{$dir}; |
|---|
| 674 |
|
|---|
| 675 |
if (defined $obfuscated_dirs{$dir}{$filename}) { |
|---|
| 676 |
$decrypt_filename = $obfuscated_dirs{$dir}{$filename}; |
|---|
| 677 |
} else { |
|---|
| 678 |
|
|---|
| 679 |
print "[-] Obfuscated file map does not exist for ", |
|---|
| 680 |
"$filename in\n $obfuscate_map_filename, ", |
|---|
| 681 |
"skipping.\n" unless $quiet; |
|---|
| 682 |
next FILE; |
|---|
| 683 |
} |
|---|
| 684 |
|
|---|
| 685 |
} else { |
|---|
| 686 |
if (not $force_mode and $file =~ /gpgdir_\d+_\d+.gpg/) { |
|---|
| 687 |
|
|---|
| 688 |
|
|---|
| 689 |
|
|---|
| 690 |
|
|---|
| 691 |
$have_obfuscated_file = 1; |
|---|
| 692 |
next FILE; |
|---|
| 693 |
} |
|---|
| 694 |
} |
|---|
| 695 |
|
|---|
| 696 |
|
|---|
| 697 |
next FILE unless length($decrypt_filename) > 0; |
|---|
| 698 |
|
|---|
| 699 |
|
|---|
| 700 |
|
|---|
| 701 |
if (-e $decrypt_filename and not $overwrite_decrypted) { |
|---|
| 702 |
print "[-] Decrypted file $dir/$decrypt_filename ", |
|---|
| 703 |
"already exists. Skipping.\n" unless $quiet; |
|---|
| 704 |
next FILE; |
|---|
| 705 |
} |
|---|
| 706 |
|
|---|
| 707 |
if ($interactive_mode) { |
|---|
| 708 |
next FILE unless (&query_yes_no( |
|---|
| 709 |
" Decrypt: $file ([y]/n)? ", $ACCEPT_YES_DEFAULT)); |
|---|
| 710 |
} |
|---|
| 711 |
|
|---|
| 712 |
unless ($trial_run) { |
|---|
| 713 |
|
|---|
| 714 |
print "[+] Decrypting: $dir/$filename\n" unless $quiet; |
|---|
| 715 |
&decrypt_file($filename, $decrypt_filename, |
|---|
| 716 |
$NO_DEL_SOURCE_FILE); |
|---|
| 717 |
|
|---|
| 718 |
if (-e $decrypt_filename && -s $decrypt_filename != 0) { |
|---|
| 719 |
|
|---|
| 720 |
|
|---|
| 721 |
unless ($no_fs_times) { |
|---|
| 722 |
if (defined $mtime and $mtime and |
|---|
| 723 |
defined $atime and $atime) { |
|---|
| 724 |
utime $atime, $mtime, $decrypt_filename; |
|---|
| 725 |
} |
|---|
| 726 |
} |
|---|
| 727 |
if ($wipe_mode and not $quiet) { |
|---|
| 728 |
print " Securely deleting file: $file\n"; |
|---|
| 729 |
} |
|---|
| 730 |
|
|---|
| 731 |
|
|---|
| 732 |
&delete_file($filename); |
|---|
| 733 |
|
|---|
| 734 |
$total_decrypted++; |
|---|
| 735 |
|
|---|
| 736 |
} else { |
|---|
| 737 |
print "[-] Could not decrypt file: $file\n" unless $quiet; |
|---|
| 738 |
next FILE; |
|---|
| 739 |
} |
|---|
| 740 |
} |
|---|
| 741 |
} |
|---|
| 742 |
} |
|---|
| 743 |
print "\n" unless $quiet; |
|---|
| 744 |
chdir $initial_dir or die "[*] Could not chdir: $initial_dir\n"; |
|---|
| 745 |
return; |
|---|
| 746 |
} |
|---|
| 747 |
|
|---|
| 748 |
sub get_files() { |
|---|
| 749 |
my $dir = shift; |
|---|
| 750 |
|
|---|
| 751 |
print "[+] Building file list...\n" unless $quiet; |
|---|
| 752 |
if ($norecurse) { |
|---|
| 753 |
opendir D, $dir or die "[*] Could not open $dir: $!"; |
|---|
| 754 |
my @files = readdir D; |
|---|
| 755 |
closedir D; |
|---|
| 756 |
|
|---|
| 757 |
for my $file (@files) { |
|---|
| 758 |
next if $file eq '.'; |
|---|
| 759 |
next if $file eq '..'; |
|---|
| 760 |
&check_file_criteria("$dir/$file"); |
|---|
| 761 |
} |
|---|
| 762 |
} else { |
|---|
| 763 |
|
|---|
| 764 |
find(\&find_files, $dir); |
|---|
| 765 |
} |
|---|
| 766 |
return; |
|---|
| 767 |
} |
|---|
| 768 |
|
|---|
| 769 |
sub exclude_file() { |
|---|
| 770 |
my $file = shift; |
|---|
| 771 |
for my $pat (@exclude_patterns) { |
|---|
| 772 |
if ($file =~ m|$pat|) { |
|---|
| 773 |
print "[+] Skipping $file (matches exclude pattern: $pat)\n" |
|---|
| 774 |
if $verbose and not $quiet; |
|---|
| 775 |
return 1; |
|---|
| 776 |
} |
|---|
| 777 |
} |
|---|
| 778 |
return 0; |
|---|
| 779 |
} |
|---|
| 780 |
|
|---|
| 781 |
sub include_file() { |
|---|
| 782 |
my $file = shift; |
|---|
| 783 |
for my $pat (@include_patterns) { |
|---|
| 784 |
if ($file =~ m|$pat|) { |
|---|
| 785 |
print "[+] Including $file (matches include pattern: $pat)\n" |
|---|
| 786 |
if $verbose and not $quiet; |
|---|
| 787 |
return 1; |
|---|
| 788 |
} |
|---|
| 789 |
} |
|---|
| 790 |
return 0; |
|---|
| 791 |
} |
|---|
| 792 |
|
|---|
| 793 |
sub obfuscated_mapping_files() { |
|---|
| 794 |
|
|---|
| 795 |
my $dirs_h |
|---|