Imported new upstream release for gpgdir.
[pgp-tools.git] / gpgdir / gpgdir
1 #!/usr/bin/perl -w
2 #
3 ###########################################################################
4 #
5 # File: gpgdir
6 #
7 # URL: http://www.cipherdyne.org/gpgdir/
8 #
9 # Purpose: To encrypt/decrypt whole directories
10 #
11 # Author: Michael Rash (mbr@cipherdyne.com)
12 #
13 # Version: 1.9.5
14 #
15 # Copyright (C) 2002-2009 Michael Rash (mbr@cipherdyne.org)
16 #
17 # License: GNU General Public License version 2 (GPLv2)
18 #
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
23 #
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 # USA
28 #
29 ###########################################################################
30 #
31 # $Id: gpgdir 341 2009-08-26 02:43:51Z mbr $
32 #
33
34 use File::Find;
35 use File::Copy;
36 use IO::File;
37 use IO::Handle;
38 use Getopt::Long;
39 use Cwd;
40 use strict;
41
42 ### set the current gpgdir version and file revision numbers
43 my $version = '1.9.5';
44 my $revision_svn = '$Revision: 341 $';
45 my $rev_num = '1';
46 ($rev_num) = $revision_svn =~ m|\$Rev.*:\s+(\S+)|;
47
48 ### establish some defaults
49 my $encrypt_user = '';
50 my $gpg_homedir = '';
51 my $dir = '';
52 my $pw = '';
53 my $encrypt_dir = '';
54 my $decrypt_dir = '';
55 my $sign_dir = '';
56 my $verify_dir = '';
57 my $homedir = '';
58 my $exclude_pat = '';
59 my $exclude_file = '';
60 my $include_pat = '';
61 my $include_file = '';
62 my $lib_dir = '/usr/lib/gpgdir';
63 my $pid_file = '';
64 my $total_encrypted = 0;
65 my $total_decrypted = 0;
66 my $norecurse = 0;
67 my $printver = 0;
68 my $no_delete = 0;
69 my $no_fs_times = 0;
70 my $test_and_exit = 0;
71 my $trial_run = 0;
72 my $skip_test_mode = 0;
73 my $verbose = 0;
74 my $quiet = 0;
75 my $use_gpg_agent = 0; ### use gpg-agent for passwords
76 my $gpg_agent_info = '';
77 my $force_mode = 0;
78 my $help = 0;
79 my $wipe_mode = 0;
80 my $encrypt_mode = 0;
81 my $signing_mode = 0;
82 my $verify_mode = 0;
83 my $use_default_key = 0;
84 my $pw_file = '';
85 my $wipe_cmd = '/usr/bin/wipe';
86 my $wipe_cmdline = '';
87 my $wipe_interactive = 0;
88 my $interactive_mode = 0;
89 my $ascii_armor_mode = 0;
90 my @exclude_patterns = ();
91 my @include_patterns = ();
92 my %files = ();
93 my %options = ();
94 my %obfuscate_ctrs = ();
95 my %obfuscated_dirs = ();
96 my $total_mapped_files = 0;
97 my $have_obfuscated_file = 0;
98 my $cmdline_no_password = 0;
99 my $obfuscate_mode = 0;
100 my $obfuscate_map_filename = '.gpgdir_map_file';
101 my $overwrite_encrypted = 0;
102 my $overwrite_decrypted = 0;
103 my $symmetric_mode = 0;
104 my $DEL_SOURCE_FILE = 1;
105 my $NO_DEL_SOURCE_FILE = 0;
106
107 my $locale = 'C'; ### default LC_ALL env variable
108 my $no_locale = 0;
109
110 ### for user answers
111 my $ACCEPT_YES_DEFAULT = 1;
112 my $ACCEPT_NO_DEFAULT = 2;
113
114 ### turn off buffering
115 $| = 1;
116
117 unless ($< == $>) {
118 die "[*] Real and effective uid must be the same. Make sure\n",
119 " gpgdir has not been installed as a SUID binary.\n",
120 "Exiting.";
121 }
122
123 my @args_cp = @ARGV;
124
125 ### make Getopts case sensitive
126 Getopt::Long::Configure('no_ignore_case');
127
128 die "[*] Use --help for usage information.\n" unless(GetOptions (
129 'encrypt-dir=s' => \$encrypt_dir, # Encrypt files in this directory.
130 'decrypt-dir=s' => \$decrypt_dir, # Decrypt files in this directory.
131 'sign-dir=s' => \$sign_dir, # Sign files in this directory.
132 'verify-dir=s' => \$verify_dir, # Verify files in this directory.
133 'gnupg-dir=s' => \$gpg_homedir, # Path to /path/to/.gnupg directory.
134 'pw-file=s' => \$pw_file, # Read password out of this file.
135 'agent' => \$use_gpg_agent, # Use gpg-agent for passwords.
136 'Agent-info=s' => \$gpg_agent_info, # Specify GnuPG agent connection
137 # information.
138 'Wipe' => \$wipe_mode, # Securely delete unencrypted files.
139 'wipe-path=s' => \$wipe_cmd, # Path to wipe command.
140 'wipe-interactive' => \$wipe_interactive, # Disable "wipe -I"
141 'wipe-cmdline=s' => \$wipe_cmdline, # Specify wipe command line.
142 'Obfuscate-filenames' => \$obfuscate_mode, # substitute real filenames
143 # with manufactured ones.
144 'obfuscate-map-file=s' => \$obfuscate_map_filename, # path to mapping file.
145 'Force' => \$force_mode, # Continue if files can't be deleted.
146 'overwrite-encrypted' => \$overwrite_encrypted, # Overwrite encrypted files
147 # even if they exist.
148 'overwrite-decrypted' => \$overwrite_decrypted, # Overwrite decrypted files
149 # even if they exist.
150 'Exclude=s' => \$exclude_pat, # Exclude a pattern from encrypt/decrypt
151 # cycle.
152 'Exclude-from=s' => \$exclude_file, # Exclude patterns in <file> from
153 # encrypt decrypt cycle.
154 'Include=s' => \$include_pat, # Specify a pattern used to restrict
155 # encrypt/decrypt operation to.
156 'Include-from=s' => \$include_file, # Specify a file of include patterns to
157 # restrict all encrypt/decrypt
158 # operations to.
159 'test-mode' => \$test_and_exit, # Run encrypt -> decrypt test only and
160 # exit.
161 'Trial-run' => \$trial_run, # Don't modify any files; just show what
162 # would have happened.
163 'quiet' => \$quiet, # Print as little as possible to
164 # stdout.
165 'Interactive' => \$interactive_mode, # Query the user before encrypting/
166 # decrypting/deleting any files.
167 'Key-id=s' => \$encrypt_user, # Specify encrypt/decrypt key
168 'Default-key' => \$use_default_key, # Assume that default-key is set within
169 # ~/.gnupg/options.
170 'Symmetric' => \$symmetric_mode, # encrypt using symmetric cipher.
171 # (this option is not required to
172 # also decrypt, GnuPG handles
173 # that automatically).
174 'Plain-ascii' => \$ascii_armor_mode, # Ascii armor mode (creates non-binary
175 # encrypted files).
176 'skip-test' => \$skip_test_mode, # Skip encrypt -> decrypt test.
177 'no-recurse' => \$norecurse, # Don't encrypt/decrypt files in
178 # subdirectories.
179 'no-delete' => \$no_delete, # Don't delete files once they have
180 # been encrypted.
181 'no-password' => \$cmdline_no_password, # Do not query for a password (only
182 # useful for when the gpg literally
183 # has no password).
184 'user-homedir=s' => \$homedir, # Path to home directory.
185 'no-preserve-times' => \$no_fs_times, # Don't preserve mtimes or atimes.
186 'LC_ALL=s' => \$locale,
187 'locale=s' => \$locale, # synonym
188 'no-LC_ALL' => \$no_locale,
189 'no-locale' => \$no_locale, # synonym
190 'Lib-dir=s' => \$lib_dir, # Path to perl module path
191 'verbose' => \$verbose, # Verbose mode.
192 'Version' => \$printver, # Print version
193 'help' => \$help # Print help
194 ));
195 &usage_and_exit() if $help;
196
197 ### set LC_ALL env variable
198 $ENV{'LC_ALL'} = $locale unless $no_locale;
199
200 print "[+] gpgdir v$version (file revision: $rev_num)\n",
201 " by Michael Rash <mbr\@cipherdyne.org>\n"
202 and exit 0 if $printver;
203
204 if ($symmetric_mode and ($use_gpg_agent or $gpg_agent_info)) {
205 die "[*] gpg-agent incompatible with --Symmetric mode";
206 }
207
208 die "[*] Cannot --sign-dir and --verify-dir"
209 if $sign_dir and $verify_dir;
210
211 if ($sign_dir) {
212 $encrypt_dir = $sign_dir;
213 $signing_mode = 1;
214 } elsif ($verify_dir) {
215 $decrypt_dir = $verify_dir;
216 $verify_mode = 1;
217 }
218
219 if ($encrypt_dir and $overwrite_decrypted) {
220 die "[*] The -e and --overwrite-decrypted options are incompatible.";
221 }
222 if ($decrypt_dir and $overwrite_encrypted) {
223 die "[*] The -d and --overwrite-encrypted options are incompatible.";
224 }
225
226 ### import perl modules (GnuPG::Interface, etc.)
227 &import_perl_modules();
228
229 if ($wipe_mode) {
230 unless (-e $wipe_cmd) {
231 die "[*] Can't find wipe command at: $wipe_cmd,\n",
232 " use --wipe-path to specify path.";
233 }
234 unless (-e $wipe_cmd) {
235 die "[*] Can't execute $wipe_cmd";
236 }
237 }
238
239 my $initial_dir = cwd or die "[*] Could not get CWD: $!";
240
241 if ($gpg_homedir) {
242 ### it was specified on the comamnd line
243 if ($gpg_homedir !~ m|^/|) {
244 $gpg_homedir = $initial_dir . '/' . $gpg_homedir;
245 }
246 }
247
248 ### build up GnuPG options hash
249 if ($verbose) {
250 %options = ('homedir' => $gpg_homedir);
251 } else {
252 %options = (
253 'batch' => 1,
254 'homedir' => $gpg_homedir
255 );
256 }
257
258 $options{'armor'} = 1 if $ascii_armor_mode or $signing_mode;
259
260 ### get the path to the user's home directory
261 $homedir = &get_homedir() unless $homedir;
262
263 unless ($symmetric_mode) {
264 unless ($gpg_homedir) {
265 $gpg_homedir = "${homedir}/.gnupg"
266 if -d "${homedir}/.gnupg";
267 }
268 unless (-d $gpg_homedir) {
269 die "[*] GnuPG directory: $gpg_homedir does not exist. Please\n",
270 " create it by executing: \"gpg --gen-key\". Exiting.\n";
271 }
272
273 ### get the key identifier from ~/.gnupg
274 $encrypt_user = &get_key() unless $encrypt_user or $use_default_key;
275 }
276
277 if ($decrypt_dir and $encrypt_dir) {
278 die "[*] Cannot encrypt and decrypt the same directory, see --help\n";
279 }
280
281 unless ($decrypt_dir or $encrypt_dir or $test_and_exit) {
282 die "[*] Please specify -e <dir>, -d <dir>, or --test-mode, see --help\n";
283 }
284
285 if ($obfuscate_mode) {
286 if ($sign_dir) {
287 die "[*] -O mode incompatible with --sign-dir";
288 } elsif ($verify_dir) {
289 die "[*] -O mode incompatible with --verify-dir";
290 }
291 }
292
293 ### exclude file pattern
294 push @exclude_patterns, $exclude_pat if $exclude_pat;
295
296 if ($exclude_file) {
297 open P, "< $exclude_file" or die "[*] Could not open file: $exclude_file";
298 my @lines = <P>;
299 close P;
300 for my $line (@lines) {
301 next unless $line =~ /\S/;
302 chomp $line;
303 push @exclude_patterns, qr{$line};
304 }
305 }
306
307 ### include file pattern
308 push @include_patterns, $include_pat if $include_pat;
309
310 if ($include_file) {
311 open P, "< $include_file" or die "[*] Could not open file: $include_file";
312 my @lines = <P>;
313 close P;
314 for my $line (@lines) {
315 next unless $line =~ /\S/;
316 chomp $line;
317 push @include_patterns, qr{$line};
318 }
319 }
320
321 if ($encrypt_dir) {
322 $dir = $encrypt_dir;
323 $encrypt_mode = 1;
324 } elsif ($decrypt_dir) {
325 $dir = $decrypt_dir;
326 $encrypt_mode = 0;
327 }
328
329 if ($dir) {
330 die "[*] Directory does not exist: $dir" unless -e $dir;
331 die "[*] Not a directory: $dir" unless -d $dir;
332 }
333
334 ### don't need to test encrypt/decrypt ability if we are running
335 ### in --Trial-run mode.
336 $skip_test_mode = 1 if $trial_run or $signing_mode or $verify_mode;
337
338 if ($dir eq '.') {
339 $dir = $initial_dir;
340 } elsif ($dir !~ m|^/|) {
341 $dir = $initial_dir . '/' . $dir;
342 }
343 $dir =~ s|/$||; ### remove any trailing slash
344
345 ### make sure another gpgdir process is not trying to operate
346 ### on the same directory
347 $pid_file = "$dir/.gpgdir.pid";
348 &unique_pid();
349 &write_pid();
350
351 if ($symmetric_mode or $signing_mode) {
352 &get_password();
353 } else {
354 &get_password() unless (($encrypt_mode and $skip_test_mode)
355 or $verify_mode);
356 }
357
358 ### run a test to make sure gpgdir and encrypt and decrypt a file
359 unless ($skip_test_mode) {
360 my $rv = &test_mode();
361 exit $rv if $test_and_exit;
362 }
363
364 if ($signing_mode) {
365 print "[+] Signing files in directory: $dir\n" unless $quiet;
366 } elsif ($encrypt_mode) {
367 print "[+] Encrypting files in directory: $dir\n" unless $quiet;
368 } elsif ($verify_mode) {
369 print "[+] Verifying signatures in directory: $dir\n" unless $quiet;
370 } else {
371 print "[+] Decrypting files in directory: $dir\n" unless $quiet;
372 }
373
374 ### build a hash of file paths to work against
375 &get_files($dir);
376
377 ### perform the gpg operation (encrypt/decrypt)
378 &gpg_operation();
379
380 &obfuscated_mapping_files() if $obfuscate_mode;
381
382 unless ($obfuscate_mode) {
383 if ($have_obfuscated_file) {
384 print "[-] Obfuscated filenames detected, try decrypting with -O\n"
385 unless $quiet;
386 }
387 }
388
389 if ($signing_mode) {
390 print "[+] Total number of files signed: " .
391 "$total_encrypted\n" unless $quiet;
392 } elsif ($encrypt_mode) {
393 print "[+] Total number of files encrypted: " .
394 "$total_encrypted\n" unless $quiet;
395 } elsif ($verify_mode) {
396 print "[+] Total number of files verified: " .
397 "$total_decrypted\n" unless $quiet;
398 } else {
399 print "[+] Total number of files decrypted: " .
400 "$total_decrypted\n" unless $quiet;
401 }
402
403 if (-e $pid_file) {
404 unlink $pid_file or die "[*] Could not remove pid file $pid_file: $!";
405 }
406
407 exit 0;
408 #==================== end main =====================
409
410 sub encrypt_or_sign_file() {
411 my ($in_file, $out_file, $del_flag) = @_;
412
413 my $gpg = GnuPG::Interface->new();
414 $gpg->options->hash_init(%options);
415
416 die "[*] Could not create new gpg object with ",
417 "homedir: $gpg_homedir" unless $gpg;
418
419 unless ($symmetric_mode or $use_default_key) {
420 $gpg->options->default_key($encrypt_user);
421 $gpg->options->push_recipients($encrypt_user);
422 }
423
424 my ($input_fh, $output_fh, $error_fh, $pw_fh, $status_fh) =
425 (IO::File->new($in_file),
426 IO::File->new("> $out_file"),
427 IO::Handle->new(),
428 IO::Handle->new(),
429 IO::Handle->new());
430
431 my $handles = GnuPG::Handles->new(
432 stdin => $input_fh,
433 stdout => $output_fh,
434 stderr => $error_fh,
435 passphrase => $pw_fh,
436 status => $status_fh
437 );
438 $handles->options('stdin')->{'direct'} = 1;
439 $handles->options('stdout')->{'direct'} = 1;
440
441 my $pid;
442
443 if ($use_gpg_agent or $gpg_agent_info) {
444
445 ### set environment explicitly if --Agent was specified
446 if ($gpg_agent_info) {
447 $ENV{'GPG_AGENT_INFO'} = $gpg_agent_info;
448 }
449
450 $pid = $gpg->encrypt('handles' => $handles,
451 'command_args' => [ qw( --use-agent ) ]);
452
453 } else {
454 if ($symmetric_mode) {
455 $pid = $gpg->encrypt_symmetrically('handles' => $handles);
456 } elsif ($signing_mode) {
457 $pid = $gpg->detach_sign('handles' => $handles);
458 } else {
459 $pid = $gpg->encrypt('handles' => $handles);
460 }
461 }
462
463 print $pw_fh $pw;
464 close $pw_fh;
465
466 my @errors = <$error_fh>;
467 close $error_fh;
468
469 my @status = <$status_fh>;
470 close $status_fh;
471
472 close $input_fh;
473 close $output_fh;
474
475 waitpid $pid, 0;
476
477 if ($verbose) {
478 print for @errors;
479 } else {
480 for (@errors) {
481 print if /bad\s+pass/;
482 }
483 }
484
485 if (-s $out_file == 0) {
486 &delete_file($out_file);
487 &delete_file($in_file) if $del_flag == $DEL_SOURCE_FILE;
488 if ($use_gpg_agent) {
489 die "[*] Created zero-size file: $out_file\n",
490 " Maybe gpg-agent does not yet have the password for that key?\n",
491 " Try with --verbose";
492 } else {
493 die "[*] Created zero-size file: $out_file\n",
494 " Bad password? Try with --verbose";
495 }
496 }
497
498 return 1;
499 }
500
501 sub decrypt_or_verify_file() {
502 my ($in_file, $out_file, $del_flag) = @_;
503
504 my $pid;
505 my $bad_passphrase = 0;
506 my $bad_signature = 0;
507 my $file_encrypted_with_expected_key = 0;
508 my $input_fh = '';
509 my $output_fh = '';
510 my $error_fh = '';
511 my $pw_fh = '';
512 my $status_fh = '';
513 my $handles = '';
514
515 my $gpg = GnuPG::Interface->new();
516 $gpg->options->hash_init(%options);
517
518 die "[*] Could not create new gpg object with ",
519 "homedir: $gpg_homedir" unless $gpg;
520
521 unless ($verify_mode or $symmetric_mode or $use_default_key) {
522 $gpg->options->default_key($encrypt_user);
523 $gpg->options->push_recipients($encrypt_user);
524 }
525
526 if ($verify_mode) {
527 ($input_fh, $output_fh, $error_fh, $status_fh) =
528 (IO::Handle->new(),
529 IO::Handle->new(),
530 IO::Handle->new(),
531 IO::Handle->new());
532 $handles = GnuPG::Handles->new(
533 stdin => $input_fh,
534 stdout => $output_fh,
535 stderr => $error_fh,
536 status => $status_fh
537 );
538 } else {
539 ($input_fh, $output_fh, $error_fh, $pw_fh, $status_fh) =
540 (IO::File->new($in_file),
541 IO::File->new("> $out_file"),
542 IO::Handle->new(),
543 IO::Handle->new(),
544 IO::Handle->new());
545 $handles = GnuPG::Handles->new(
546 stdin => $input_fh,
547 stdout => $output_fh,
548 stderr => $error_fh,
549 passphrase => $pw_fh,
550 status => $status_fh
551 );
552 $handles->options('stdin')->{'direct'} = 1;
553 $handles->options('stdout')->{'direct'} = 1;
554 }
555
556 if ($use_gpg_agent) {
557 $pid = $gpg->decrypt('handles' => $handles,
558 'command_args' => [ qw( --use-agent ) ]);
559 } else {
560 if ($verify_mode) {
561 $pid = $gpg->wrap_call(
562 'commands' => [ qw( --verify ) ],
563 'command_args' => [ ( $in_file ) ],
564 'handles' => $handles
565 );
566 } else {
567 $pid = $gpg->decrypt('handles' => $handles);
568 }
569 }
570
571 unless ($verify_mode) {
572 print $pw_fh $pw;
573 close $pw_fh;
574 }
575
576 my @errors = <$error_fh>;
577 close $error_fh;
578
579 my @status = <$status_fh>;
580 close $status_fh;
581
582 close $input_fh;
583 close $output_fh;
584
585 waitpid $pid, 0;
586
587 for (@status) {
588 if ($verify_mode) {
589 ### [GNUPG:] BADSIG 9EEEEE6BEE428EEE Some User <someone@domain.com>
590 $bad_signature = 1 if /BADSIG/;
591 } else {
592 ### [GNUPG:] BAD_PASSPHRASE C326F95CE133EA4E
593 $bad_passphrase = 1 if /BAD_?PASS/;
594 if (/NEED_PASSPHRASE\s\S+\s+\S+$encrypt_user\s/) {
595 ### [GNUPG:] NEED_PASSPHRASE CDE4D7DDFD66DCB9 95D85DDDDD42D39D 16 0
596 $file_encrypted_with_expected_key = 1;
597 } elsif ((length($encrypt_user) == 8)
598 and /USERID_HINT\s+.*$encrypt_user/) {
599 $file_encrypted_with_expected_key = 1;
600 }
601 }
602 }
603
604 if ($verbose) {
605 print " GnuPG errors:\n";
606 print for @errors;
607 print " GnuPG status:\n";
608 print for @status;
609 } else {
610 for (@status) {
611 if (/BAD_?PASS/) {
612 print unless $quiet;
613 } elsif (/BADSIG/) {
614 print unless $quiet;
615 }
616 }
617 }
618
619 if ($bad_passphrase) {
620 if (-s $out_file == 0) {
621 &delete_file($out_file);
622 &delete_file($in_file) if $del_flag == $DEL_SOURCE_FILE;
623 if ($file_encrypted_with_expected_key) {
624 die "[*] Bad passphrase, try gpgdir with -v";
625 } else {
626 print "[-] Skipping file encrypted with different ",
627 "GnuPG key: $in_file\n" unless $quiet;
628 }
629 } else {
630 die
631 "[*] Bad passphrase, but created non-zero sized output file, should not\n",
632 " happen. Try with --verbose";
633 }
634 } elsif (-s $out_file == 0) {
635 &delete_file($out_file);
636 &delete_file($in_file) if $del_flag == $DEL_SOURCE_FILE;
637 if ($use_gpg_agent) {
638 die "[*] Created zero-size file: $out_file\n",
639 " Maybe gpg-agent does not yet have the password for that key?\n",
640 " Try with --verbose";
641 } else {
642 die "[*] Created zero-size file: $out_file\n",
643 " Bad password? Try with --verbose";
644 }
645 }
646 if ($bad_signature) {
647 return 0;
648 }
649 return 1;
650 }
651
652 sub delete_file() {
653 my $file = shift;
654
655 return if $no_delete;
656 return unless -e $file;
657
658 if ($wipe_mode) {
659 my $cmd = $wipe_cmd;
660 if ($wipe_cmdline) {
661 $cmd .= " $wipe_cmdline ";
662 } else {
663 if ($wipe_interactive) {
664 $cmd .= ' -i ';
665 } else {
666 $cmd .= ' -f -s ';
667 }
668 }
669 $cmd .= qq|"$file"|;
670 if ($verbose) {
671 print " Executing: $cmd\n";
672 }
673
674 ### wipe the file
675 system $cmd;
676
677 } else {
678 unlink $file;
679 }
680
681 if (-e $file) {
682 my $msg = "[-] Could not delete file: $file\n";
683 if ($force_mode) {
684 print $msg unless $quiet;
685 } else {
686 die $msg unless $quiet;
687 }
688 }
689 return;
690 }
691
692 sub gpg_operation() {
693
694 ### sort by oldest to youngest mtime
695 FILE: for my $file (sort
696 {$files{$a}{'mtime'} <=> $files{$b}{'mtime'}} keys %files) {
697
698 ### see if we have an exclusion pattern that implies
699 ### we should skip this file
700 if (@exclude_patterns and &exclude_file($file)) {
701 print "[+] Skipping excluded file: $file\n"
702 if $verbose and not $quiet;
703 next FILE;
704 }
705
706 ### see if we have an inclusion pattern that implies
707 ### we should process this file
708 if (@include_patterns and not &include_file($file)) {
709 print "[+] Skipping non-included file: $file\n"
710 if $verbose and not $quiet;
711 next FILE;
712 }
713
714 ### dir is always a full path
715 my ($dir, $filename) = ($file =~ m|(.*)/(.*)|);
716
717 unless (chdir($dir)) {
718 print "[-] Could not chdir $dir, skipping.\n" unless $quiet;
719 next FILE;
720 }
721
722 my $mtime = $files{$file}{'mtime'};
723 my $atime = $files{$file}{'atime'};
724
725 if ($encrypt_mode) {
726
727 my $encrypt_filename = "$filename.gpg";
728
729 if ($obfuscate_mode) {
730
731 unless (defined $obfuscate_ctrs{$dir}) {
732
733 ### create a new gpgdir mapping file for obfuscated file
734 ### names, but preserve any previously encrypted file
735 ### name mappings
736 &handle_old_obfuscated_map_file();
737
738 ### make obfuscated file names start at 1 for each
739 ### directory
740 $obfuscate_ctrs{$dir} = 1;
741 }
742
743 $encrypt_filename = 'gpgdir_' . $obfuscate_ctrs{$dir} . '.gpg';
744 }
745
746 if ($ascii_armor_mode or $signing_mode) {
747 $encrypt_filename = "$filename.asc";
748 }
749
750 if (-e $encrypt_filename and not $overwrite_encrypted) {
751 my $str = 'Encrypted';
752 $str = 'Signed' if $signing_mode;
753 print "[-] $str file $dir/$encrypt_filename already ",
754 "exists, skipping.\n" unless $quiet;
755 next FILE;
756 }
757
758 if ($interactive_mode) {
759 my $str = 'Encrypt';
760 $str = 'Sign' if $signing_mode;
761 next FILE unless (&query_yes_no(
762 " $str: $file ([y]/n)? ", $ACCEPT_YES_DEFAULT));
763 }
764
765 my $str = 'Encrypting';
766 $str = 'Signing' if $signing_mode;
767 print "[+] $str: $file\n" unless $quiet;
768
769 unless ($trial_run) {
770
771 my $rv = &encrypt_or_sign_file($filename, $encrypt_filename,
772 $NO_DEL_SOURCE_FILE);
773
774 if (-e $encrypt_filename and -s $encrypt_filename != 0) {
775 ### set the atime and mtime to be the same as the
776 ### original file.
777 unless ($no_fs_times) {
778 if (defined $mtime and $mtime and
779 defined $atime and $atime) {
780 utime $atime, $mtime, $encrypt_filename;
781 }
782 }
783
784 unless ($signing_mode) {
785 ### only delete the original file if
786 ### the encrypted one exists
787 if ($wipe_mode and not $quiet) {
788 print " Securely deleting file: $file\n";
789 }
790 &delete_file($filename);
791
792 if ($obfuscate_mode) {
793
794 ### record the original file name mapping
795 &append_obfuscated_mapping($filename,
796 $encrypt_filename);
797
798 $obfuscate_ctrs{$dir}++;
799 }
800 }
801
802 $total_encrypted++;
803
804 } else {
805 my $str = 'encrypt';
806 $str = 'sign' if $signing_mode;
807 print "[-] Could not $str file: $file\n" unless $quiet;
808 next FILE;
809 }
810 }
811
812 } else {
813
814 ### allow filenames with spaces
815 my $decrypt_filename = '';
816 if ($filename =~ /^(.+)\.gpg$/) {
817 $decrypt_filename = $1;
818 } elsif ($filename =~ /^(.+)\.asc$/) {
819 $decrypt_filename = $1;
820 } elsif ($filename =~ /^(.+)\.pgp$/) {
821 $decrypt_filename = $1;
822 }
823
824 if ($obfuscate_mode) {
825
826 &import_obfuscated_file_map($dir)
827 unless defined $obfuscated_dirs{$dir};
828
829 if (defined $obfuscated_dirs{$dir}{$filename}) {
830 $decrypt_filename = $obfuscated_dirs{$dir}{$filename};
831 } else {
832 ###
833 print "[-] Obfuscated file map does not exist for ",
834 "$filename in\n $obfuscate_map_filename, ",
835 "skipping.\n" unless $quiet;
836 next FILE;
837 }
838
839 } else {
840 if (not $force_mode and ($file =~ /gpgdir_\d+_\d+\.gpg/
841 or $file =~ /gpgdir_\d+\.gpg/)) {
842 ### be careful not to decrypt obfuscated file unless we
843 ### are running in -O mode. This ensures that the
844 ### original file names will be acquired from the
845 ### /some/dir/.gpgdir_map_file
846 $have_obfuscated_file = 1;
847 next FILE;
848 }
849 }
850
851 ### length() allows files named "0"
852 next FILE unless length($decrypt_filename) > 0;
853
854 if ($verify_mode) {
855 unless (-e $decrypt_filename) {
856 print "[-] Original file $decrypt_filename ",
857 "does not exist, skipping.\n";
858 next FILE;
859 }
860 } else {
861 ### don't decrypt a file on top of a normal file of
862 ### the same name
863 if (-e $decrypt_filename and not $overwrite_decrypted) {
864 print "[-] Decrypted file $dir/$decrypt_filename ",
865 "already exists. Skipping.\n" unless $quiet;
866 next FILE;
867 }
868 }
869
870 if ($interactive_mode) {
871 my $str = 'Decrypt';
872 $str = 'Verify' if $verify_mode;
873 next FILE unless (&query_yes_no(
874 " $str: $file ([y]/n)? ", $ACCEPT_YES_DEFAULT));
875 }
876
877 unless ($trial_run) {
878 my $str = 'Decrypting';
879 $str = 'Verifying' if $verify_mode;
880 print "[+] $str: $dir/$filename\n" unless $quiet;
881 my $rv = &decrypt_or_verify_file($filename, $decrypt_filename,
882 $NO_DEL_SOURCE_FILE);
883
884 if ($verify_mode) {
885 $total_decrypted++ if $rv;
886 } else {
887 if (-e $decrypt_filename and -s $decrypt_filename != 0) {
888 ### set the atime and mtime to be the same as the
889 ### original file.
890 unless ($no_fs_times) {
891 if (defined $mtime and $mtime and
892 defined $atime and $atime) {
893 utime $atime, $mtime, $decrypt_filename;
894 }
895 }
896 if ($wipe_mode and not $quiet) {
897 print " Securely deleting file: $file\n";
898 }
899 ### only delete the original encrypted
900 ### file if the decrypted one exists
901 &delete_file($filename);
902
903 $total_decrypted++;
904
905 } else {
906 print "[-] Could not decrypt file: $file\n"
907 unless $quiet;
908 next FILE;
909 }
910 }
911 }
912 }
913 }
914 print "\n" unless $quiet;
915 chdir $initial_dir or die "[*] Could not chdir: $initial_dir\n";
916 return;
917 }
918
919 sub get_files() {
920 my $dir = shift;
921
922 print "[+] Building file list...\n" unless $quiet;
923 if ($norecurse) {
924 opendir D, $dir or die "[*] Could not open $dir: $!";
925 my @files = readdir D;
926 closedir D;
927
928 for my $file (@files) {
929 next if $file eq '.';
930 next if $file eq '..';
931 &check_file_criteria("$dir/$file");
932 }
933 } else {
934 ### get all files in all subdirectories
935 find(\&find_files, $dir);
936 }
937 return;
938 }
939
940 sub exclude_file() {
941 my $file = shift;
942 for my $pat (@exclude_patterns) {
943 if ($file =~ m|$pat|) {
944 print "[+] Skipping $file (matches exclude pattern: $pat)\n"
945 if $verbose and not $quiet;
946 return 1;
947 }
948 }
949 return 0;
950 }
951
952 sub include_file() {
953 my $file = shift;
954 for my $pat (@include_patterns) {
955 if ($file =~ m|$pat|) {
956 print "[+] Including $file (matches include pattern: $pat)\n"
957 if $verbose and not $quiet;
958 return 1;
959 }
960 }
961 return 0;
962 }
963
964 sub obfuscated_mapping_files() {
965
966 my $dirs_href = {};
967
968 if ($encrypt_mode) {
969 $dirs_href = \%obfuscate_ctrs;
970 } else {
971 $dirs_href = \%obfuscated_dirs;
972 }
973
974 DIR: for my $dir (keys %$dirs_href) {
975 unless (chdir($dir)) {
976 print "[-] Could not chdir $dir, skipping.\n" unless $quiet;
977 next DIR;
978 }
979
980 if ($encrypt_mode) {
981 next DIR unless -e $obfuscate_map_filename;
982 ### encrypt the map file now that we have encrypted
983 ### the directory
984 print "[+] Encrypting mapping file: ",
985 "$dir/$obfuscate_map_filename\n" unless $quiet;
986 unless ($trial_run) {
987 &encrypt_or_sign_file($obfuscate_map_filename,
988 "$obfuscate_map_filename.gpg", $NO_DEL_SOURCE_FILE);
989
990 unlink $obfuscate_map_filename;
991 }
992 } else {
993 next DIR unless -e "$obfuscate_map_filename.gpg";
994 ### delete the map file since we have decrypted
995 ### the directory
996 print "[+] Decrypting mapping file: ",
997 "$dir/$obfuscate_map_filename.gpg\n" unless $quiet;
998 unless ($trial_run) {
999 &decrypt_or_verify_file("$obfuscate_map_filename.gpg",
1000 $obfuscate_map_filename, $NO_DEL_SOURCE_FILE);
1001
1002 unlink "$obfuscate_map_filename.gpg";
1003 if ($total_mapped_files == $total_decrypted) {
1004 ### we are confident that we decrypted all of them,
1005 ### so delete the mapping file.
1006 unlink $obfuscate_map_filename;
1007 }
1008 }
1009 }
1010 }
1011 return;
1012 }
1013
1014 sub handle_old_obfuscated_map_file() {
1015 return unless -e "$obfuscate_map_filename.gpg";
1016
1017 &decrypt_or_verify_file("$obfuscate_map_filename.gpg",
1018 $obfuscate_map_filename, $NO_DEL_SOURCE_FILE);
1019
1020 unlink "$obfuscate_map_filename.gpg";
1021
1022 my @existing_obfuscated_files = ();
1023
1024 open F, "< $obfuscate_map_filename" or die "[*] Could not open ",
1025 "$obfuscate_map_filename: $!";
1026 while (<F>) {
1027 if (/^\s*.*\s+(gpgdir_\d+_\d+\.gpg)/) {
1028 if (-e $1) {
1029 push @existing_obfuscated_files, $_;
1030 }
1031 } elsif (/^\s*.*\s+(gpgdir_\d+\.gpg)/) {
1032 if (-e $1) {
1033 push @existing_obfuscated_files, $_;
1034 }
1035 }
1036 }
1037 close F;
1038
1039 if (@existing_obfuscated_files) {
1040 ### there are some obfuscated files from a previous gpgdir
1041 ### execution
1042 open G, "> $obfuscate_map_filename" or die "[*] Could not open ",
1043 "$obfuscate_map_filename: $!";
1044 print G for @existing_obfuscated_files;
1045 close G;
1046 }
1047 return;
1048 }
1049
1050 sub append_obfuscated_mapping() {
1051 my ($filename, $encrypt_filename) = @_;
1052
1053 open G, ">> $obfuscate_map_filename" or die "[*] Could not open ",
1054 "$obfuscate_map_filename: $!";
1055 print G "$filename $encrypt_filename\n";
1056 close G;
1057 return;
1058 }
1059
1060 sub import_obfuscated_file_map() {
1061 my $dir = shift;
1062
1063 $obfuscated_dirs{$dir} = {};
1064
1065 return unless -e "$obfuscate_map_filename.gpg";
1066
1067 &decrypt_or_verify_file("$obfuscate_map_filename.gpg",
1068 $obfuscate_map_filename, $NO_DEL_SOURCE_FILE);
1069
1070 open G, "< $obfuscate_map_filename" or die "[*] Could not open ",
1071 "$obfuscate_map_filename: $!";
1072 while (<G>) {
1073 if (/^\s*(.*)\s+(gpgdir_\d+_\d+\.gpg)/) {
1074 $obfuscated_dirs{$dir}{$2} = $1;
1075 $total_mapped_files++;
1076 } elsif (/^\s*(.*)\s+(gpgdir_\d+\.gpg)/) {
1077 $obfuscated_dirs{$dir}{$2} = $1;
1078 $total_mapped_files++;
1079 }
1080 }
1081 close G;
1082
1083 return;
1084 }
1085
1086 sub get_homedir() {
1087 my $uid = $<;
1088 my $homedir = '';
1089 if (-e '/etc/passwd') {
1090 open P, '< /etc/passwd' or
1091 die "[*] Could not open /etc/passwd. Exiting.\n";
1092 my @lines = <P>;
1093 close P;
1094 for my $line (@lines) {
1095 ### mbr:x:222:222:Michael Rash:/home/mbr:/bin/bash
1096 chomp $line;
1097 if ($line =~ /^(?:.*:){2}$uid:(?:.*:){2}(\S+):/) {
1098 $homedir = $1;
1099 last;
1100 }
1101 }
1102 } else {
1103 $homedir = $ENV{'HOME'} if defined $ENV{'HOME'};
1104 }
1105 die "[*] Could not determine home directory. Use the -u <homedir> option."
1106 unless $homedir;
1107 return $homedir;
1108 }
1109
1110 sub get_key() {
1111 if (-e "${homedir}/.gpgdirrc") {
1112 open F, "< ${homedir}/.gpgdirrc" or die "[*] Could not open ",
1113 "${homedir}/.gpgdirrc. Exiting.\n";
1114 my @lines = <F>;
1115 close F;
1116 my $key = '';
1117 for my $line (@lines) {
1118 chomp $line;
1119 if ($line =~ /^\s*default_key/) {
1120 ### prefer to use the default GnuPG key
1121 $use_default_key = 1;
1122 return '';
1123 } elsif ($line =~ /^\s*use_key\s+(.*)$/) {
1124 ### GnuPG accepts strings to match the key, so we don't
1125 ### have to strictly require a key ID... just a string
1126 ### that matches the key
1127 return $1;
1128 }
1129 }
1130 die
1131 "[*] Please edit ${homedir}/.gpgdirrc to include your gpg key identifier\n",
1132 " (e.g. \"D4696445\"; see the output of \"gpg --list-keys\"), or use the\n",
1133 " default GnuPG key defined in ~/.gnupg/options";
1134 }
1135 print "[+] Creating gpgdir rc file: $homedir/.gpgdirrc\n";
1136 open F, "> ${homedir}/.gpgdirrc" or die "[*] Could not open " .
1137 "${homedir}/.gpgdirrc. Exiting.\n";
1138
1139 print F <<_CONFIGRC_;
1140 # Config file for gpgdir.
1141 #
1142 # Set the key to use to encrypt files with "use_key <key>", e.g.
1143 # "use_key D4696445". See "gpg --list-keys" for a list of keys on your
1144 # GnuPG key ring. Alternatively, if you want gpgdir to always use the
1145 # default key that is defined by the "default-key" variable in
1146 # ~/.gnupg/options, then uncomment the "default_key" line below.
1147
1148 # Uncomment to use the GnuPG default key defined in ~/.gnupg/options:
1149 #default_key
1150
1151 # If you want to use a specific GnuPG key, Uncomment the next line and
1152 # replace "KEYID" with your real key id:
1153 #use_key KEYID
1154 _CONFIGRC_
1155
1156 close F;
1157 die
1158 "[*] Please edit $homedir/.gpgdirrc to include your gpg key identifier,\n",
1159 " or use the default GnuPG key defined in ~/.gnupg/options. Exiting.\n";
1160 }
1161
1162 sub find_files() {
1163 my $file = $File::Find::name;
1164 &check_file_criteria($file);
1165 return;
1166 }
1167
1168 sub check_file_criteria() {
1169 my $file = shift;
1170 ### skip all links, zero size files, all hidden
1171 ### files (includes the .gnupg directory), etc.
1172 return if -d $file;
1173
1174 unless ($force_mode) {
1175 if ($file =~ m|/\.|) {
1176 print "[-] Skipping file: $file\n"
1177 if $verbose and not $quiet;
1178 return;
1179 }
1180 }
1181
1182 if (-e $file and not -l $file and -s $file != 0
1183 and $file !~ m|\.gpgdir\.pid| and $file !~ m|\.gnupg|) {
1184 if ($encrypt_mode or $signing_mode) {
1185 if ($file =~ m|\.gpg| or $file =~ m|\.asc| or $file =~ m|\.pgp|) {
1186 print "[-] Skipping encrypted/signed file: $file\n" unless $quiet;
1187 return;
1188 }
1189 } elsif ($verify_mode) {
1190 unless ($file =~ m|\.asc|) {
1191 ### only pick up the signature files
1192 return;
1193 }
1194 } else {
1195 unless ($file =~ m|\.gpg| or $file =~ m|\.asc|
1196 or $file =~ m|\.pgp|) {
1197 print "[-] Skipping unencrypted file: $file\n" unless $quiet;
1198 return;
1199 }
1200 }
1201 my ($atime, $mtime) = (stat($file))[8,9];
1202 $files{$file}{'atime'} = $atime;
1203 $files{$file}{'mtime'} = $mtime;
1204 } else {
1205 print "[-] Skipping file: $file\n"
1206 if $verbose and not $quiet;
1207 }
1208 return;
1209 }
1210
1211 sub get_password() {
1212
1213 ### this is only useful if the gpg key literally has no password
1214 ### (usually this is not the case, but gpgdir will support it if
1215 ### so).
1216 return if $cmdline_no_password;
1217
1218 ### if we are using gpg-agent for passwords, then return
1219 return if $use_gpg_agent;
1220
1221 if ($pw_file) {
1222 open PW, "< $pw_file" or die "[*] Could not open $pw_file: $!";
1223 $pw = <PW>;
1224 close PW;
1225 chomp $pw;
1226 } else {
1227 print "[+] Executing: gpgdir @args_cp\n" unless $quiet;
1228 if ($symmetric_mode) {
1229 print " [Symmetric mode]\n" unless $quiet;
1230 } else {
1231 if ($use_default_key) {
1232 print " Using default GnuPG key.\n" unless $quiet;
1233 } else {
1234 print " Using GnuPG key: $encrypt_user\n" unless $quiet;
1235 }
1236 }
1237 if ($test_and_exit) {
1238 print " *** test_mode() ***\n" unless $quiet;
1239 }
1240 if ($signing_mode) {
1241 print " Enter signing password.\n" unless $quiet;
1242 } elsif ($encrypt_mode) {
1243 print ' Enter password (for initial ' .
1244 "encrypt/decrypt test)\n" unless $quiet;
1245 }
1246 my $msg = 'Password: ';
1247 ### get the password without echoing the chars back to the screen
1248 ReadMode('noecho');
1249 while (not $pw) {
1250 print $msg;
1251 $pw = ReadLine(0);
1252 chomp $pw;
1253 }
1254 ReadMode('normal');
1255 if ($quiet) {
1256 print "\n";
1257 } else {
1258 print "\n\n";
1259 }
1260 }
1261 return;
1262 }
1263
1264 sub test_mode() {
1265 chdir $dir or die "[*] Could not chdir($dir): $!";
1266
1267 my $test_file = "gpgdir_test.$$";
1268 print "[+] test_mode(): Encrypt/Decrypt test of $test_file\n"
1269 if (($test_and_exit or $verbose) and not $quiet);
1270
1271 if (-e $test_file) {
1272 &delete_file($test_file) or
1273 die "[*] test_mode(): Could not remove $test_file: $!";
1274 }
1275 if (-e "$test_file.gpg") {
1276 &delete_file("$test_file.gpg") or
1277 die "[*] test_mode(): Could not remove $test_file.gpg: $!";
1278 }
1279
1280 open G, "> $test_file" or
1281 die "[*] test_mode(): Could not create $test_file: $!";
1282 print G "gpgdir test\n";
1283 close G;
1284
1285 if (-e $test_file) {
1286 print "[+] test_mode(): Created $test_file\n"
1287 if (($test_and_exit or $verbose) and not $quiet);
1288 } else {
1289 die "[*] test_mode(): Could not create $test_file\n";
1290 }
1291
1292 &encrypt_or_sign_file($test_file, "${test_file}.gpg", $DEL_SOURCE_FILE);
1293
1294 if (-e "$test_file.gpg" and (-s $test_file != 0)) {
1295 print "[+] test_mode(): Successful encrypt of $test_file\n"
1296 if (($test_and_exit or $verbose) and not $quiet);
1297 &delete_file($test_file) if -e $test_file;
1298 } else {
1299 die "[*] test_mode(): not encrypt $test_file (try adding -v).\n";
1300 }
1301
1302 &decrypt_or_verify_file("${test_file}.gpg", $test_file, $DEL_SOURCE_FILE);
1303
1304 if (-e $test_file and (-s $test_file != 0)) {
1305 print "[+] test_mode(): Successful decrypt of $test_file\n"
1306 if (($test_and_exit or $verbose) and not $quiet);
1307 } else {
1308 die "[*] test_mode(): Could not decrypt $test_file.gpg ",
1309 "(try adding -v).\n";
1310 }
1311 open F, "< $test_file" or
1312 die "[*] test_mode(): Could not open $test_file: $!";
1313 my $line = <F>;
1314 close F;
1315
1316 if (defined $line and $line =~ /\S/) {
1317 chomp $line;
1318 if ($line eq 'gpgdir test') {
1319 print "[+] test_mode(): Decrypted content matches original.\n",
1320 "[+] test_mode(): Success!\n\n"
1321 if (($test_and_exit or $verbose) and not $quiet);
1322 } else {
1323 die "[*] test_mode(): Decrypted content does not match ",
1324 "original (try adding -v).";
1325 }
1326 } else {
1327 die "[*] test_mode(): Fail (try adding -v).\n";
1328 }
1329 &delete_file($test_file) if -e $test_file;
1330 &delete_file("$test_file.gpg") if -e "$test_file.gpg";
1331
1332 chdir $initial_dir or die "[*] Could not chdir($initial_dir)";
1333
1334 return 0; ### exit status
1335 }
1336
1337 sub query_yes_no() {
1338 my ($msg, $style) = @_;
1339 my $ans = '';
1340 while ($ans ne 'y' and $ans ne 'n') {
1341 print $msg;
1342 $ans = lc(<STDIN>);
1343 if ($style == $ACCEPT_YES_DEFAULT) {
1344 return 1 if $ans eq "\n";
1345 } elsif ($style == $ACCEPT_NO_DEFAULT) {
1346 return 0 if $ans eq "\n";
1347 }
1348 chomp $ans;
1349 }
1350 return 1 if $ans eq 'y';
1351 return 0;
1352 }
1353
1354 sub unique_pid() {
1355 return unless -e $pid_file;
1356 open P, "< $pid_file" or die "[*] Could not open $pid_file: $!";
1357 my $pid = <P>;
1358 chomp $pid;
1359 close P;
1360 if (kill 0, $pid) {
1361 die "[*] Another gpgdir process (pid: $pid) is already ",
1362 "running against\n $dir";
1363 }
1364 return;
1365 }
1366
1367 sub write_pid() {
1368 open P, "> $pid_file" or die "[*] Could not open $pid_file: $!";
1369 print P $$, "\n";
1370 close P;
1371 return;
1372 }
1373
1374 sub import_perl_modules() {
1375
1376 my $mod_paths_ar = &get_mod_paths();
1377
1378 if ($#$mod_paths_ar > -1) { ### /usr/lib/gpgdir/ exists
1379 push @$mod_paths_ar, @INC;
1380 splice @INC, 0, $#$mod_paths_ar+1, @$mod_paths_ar;
1381 }
1382
1383 if ($verbose) {
1384 print "[+] import_perl_modules(): The \@INC array:\n";
1385 print "$_\n" for @INC;
1386 }
1387
1388 require GnuPG::Interface;
1389 require Term::ReadKey;
1390
1391 Term::ReadKey->import(qw/ReadMode ReadLine/);
1392
1393 return;
1394 }
1395
1396 sub get_mod_paths() {
1397
1398 my @paths = ();
1399
1400 unless (-d $lib_dir) {
1401 my $dir_tmp = $lib_dir;
1402 $dir_tmp =~ s|lib/|lib64/|;
1403 if (-d $dir_tmp) {
1404 $lib_dir = $dir_tmp;
1405 } else {
1406 return [];
1407 }
1408 }
1409
1410 opendir D, $lib_dir or die "[*] Could not open $lib_dir: $!";
1411 my @dirs = readdir D;
1412 closedir D;
1413
1414 push @paths, $lib_dir;
1415
1416 for my $dir (@dirs) {
1417 ### get directories like "/usr/lib/gpgdir/x86_64-linux"
1418 next unless -d "$lib_dir/$dir";
1419 push @paths, "$lib_dir/$dir"
1420 if $dir =~ m|linux| or $dir =~ m|thread|
1421 or (-d "$lib_dir/$dir/auto");
1422 }
1423 return \@paths;
1424 }
1425
1426 sub usage_and_exit() {
1427 print <<_HELP_;
1428
1429 gpgdir; Recursive direction encryption and decryption with GnuPG
1430
1431 [+] Version: $version (file revision: $rev_num)
1432 By Michael Rash (mbr\@cipherdyne.org)
1433 URL: http://www.cipherdyne.org/gpgdir/
1434
1435 Usage: gpgdir -e|-d <directory> [options]
1436
1437 Options:
1438 -e, --encrypt <directory> - Recursively encrypt all files in
1439 <directory> and all subdirectories.
1440 -d, --decrypt <directory> - Recursively decrypt all files in
1441 <directory> and all subdirectories.
1442 --sign <directory> - Recursively sign all files in <directory>
1443 and all subdirectories.
1444 --verify <directory> - Recursively verify all GnuPG signatures
1445 in <directory>.
1446 -K, --Key-id <id> - Specify GnuPG key ID, or key-matching
1447 string. This overrides the use_key value
1448 in ~/.gpgdirrc
1449 -D, --Default-key - Use the key that GnuPG defines as the
1450 default (i.e. the key that is specified
1451 by the default-key option in
1452 ~/.gnupg/options).
1453 -a, --agent - Acquire password information from a
1454 running instance of gpg-agent.
1455 -A, --Agent-info <info> - Specify the value for the GPG_AGENT_INFO
1456 environment variable as returned by
1457 'gpg-agent --daemon'.
1458 -g, --gnupg-dir <dir> - Specify a path to a .gnupg directory for
1459 gpg keys (the default is ~/.gnupg if this
1460 option is not used).
1461 -S, --Symmetric - Use symmetric encryption instead of the
1462 default asymmetric encryption.
1463 -p, --pw-file <file> - Read password in from <file>.
1464 --skip-test - Skip encrypt -> decrypt test.
1465 -t, --test-mode - Run encrypt -> decrypt test and exit.
1466 -T, --Trial-run - Show what filesystem actions would take
1467 place without actually doing them.
1468 -P, --Plain-ascii - Ascii armor mode (creates non-binary
1469 encrypted files).
1470 --Interactive - Query the user before encrypting,
1471 decrypting, or deleting any files.
1472 --Exclude <pattern> - Skip all filenames that match <pattern>.
1473 --Exclude-from <file> - Skip all filenames that match any pattern
1474 contained within <file>.
1475 --Include <pattern> - Include only those filenames that match
1476 <pattern>.
1477 --Include-from <file> - Include only those filenames that match a
1478 pattern contained within <file>.
1479 -O, --Obfuscate-filenames - Substitute all real filenames in a
1480 directory with manufactured ones (the
1481 original filenames are preserved in a
1482 mapping file and restored when the
1483 directory is decrypted).
1484 --obfuscate-map_file <file> - Specify path to obfuscated mapping file
1485 (in -O mode).
1486 -F, --Force - Continue to run even if files cannot be
1487 deleted (because of permissions problems
1488 for example).
1489 --overwrite-encrypted - Overwrite encrypted files even if a
1490 previous <file>.gpg file already exists.
1491 --overwrite-decrypted - Overwrite decrypted files even if the
1492 previous unencrypted file already exists.
1493 -q, --quiet - Print as little to the screen as possible
1494 -W, --Wipe - Use the 'wipe' command to securely delete
1495 unencrypted copies of files after they
1496 have been encrypted.
1497 --wipe-path <path> - Specify path to the wipe command.
1498 --wipe-interactive - Force interactive mode with the wipe
1499 command.
1500 --wipe-cmdline <args> - Manually specify command line arguments
1501 to the wipe command.
1502 --no-recurse - Don't recursively encrypt/decrypt
1503 subdirectories.
1504 --no-delete - Don't delete original unencrypted files.
1505 --no-preserve-times - Don't preserve original mtime and atime
1506 values on encrypted/decrypted files.
1507 --no-password - Assume the gpg key has no password at all
1508 (this is not common).
1509 -u, --user-homedir <dir> - Path to home directory.
1510 -l, --locale <locale> - Manually define a locale setting.
1511 --Lib-dir <path> - Path to the perl modules directory (not
1512 usually necessary).
1513 --no-locale - Don't set the locale to anything (the
1514 default is the "C" locale).
1515 --verbose - Run in verbose mode.
1516 -V, --Version - print version.
1517 -h, --help - print help.
1518 _HELP_
1519 exit 0;
1520 }