3 ###########################################################################
7 # URL: http://www.cipherdyne.org/gpgdir/
9 # Purpose: To encrypt/decrypt whole directories
11 # Author: Michael Rash (mbr@cipherdyne.com)
15 # Copyright (C) 2002-2007 Michael Rash (mbr@cipherdyne.org)
17 # License (GNU General Public License):
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.
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
29 ###########################################################################
31 # $Id: gpgdir 246 2008-02-18 14:29:16Z mbr $
34 use lib
'/usr/lib/gpgdir';
45 ### set the current gpgdir version and file revision numbers
47 my $revision_svn = '$Revision: 246 $';
49 ($rev_num) = $revision_svn =~ m
|\
$Rev.*:\s
+(\S
+)|;
51 ### establish some defaults
52 my $encrypt_user = '';
60 my $exclude_file = '';
62 my $include_file = '';
63 my $total_encrypted = 0;
64 my $total_decrypted = 0;
69 my $test_and_exit = 0;
71 my $skip_test_mode = 0;
74 my $use_gpg_agent = 0; ### use gpg-agent for passwords
75 my $gpg_agent_info = '';
80 my $use_default_key = 0;
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 = ();
91 my %obfuscate_ctrs = ();
92 my %obfuscated_dirs = ();
93 my $have_obfuscated_file = 0;
94 my $cmdline_no_password = 0;
95 my $obfuscate_mode = 0;
96 my $obfuscate_map_filename = '.gpgdir_map_file';
97 my $overwrite_encrypted = 0;
98 my $overwrite_decrypted = 0;
99 my $symmetric_mode = 0;
100 my $DEL_SOURCE_FILE = 1;
101 my $NO_DEL_SOURCE_FILE = 0;
104 my $ACCEPT_YES_DEFAULT = 1;
105 my $ACCEPT_NO_DEFAULT = 2;
108 die "[*] Real and effective uid must be the same. Make sure\n",
109 " gpgdir has not been installed as a SUID binary.\n",
115 ### make Getopts case sensitive
116 Getopt
::Long
::Configure
('no_ignore_case');
118 die "[-] Use --help for usage information.\n" unless(GetOptions
(
119 'encrypt=s' => \
$encrypt_dir, # Encrypt files in this directory.
120 'decrypt=s' => \
$decrypt_dir, # Decrypt files in this directory.
121 'gnupg-dir=s' => \
$gpg_homedir, # Path to /path/to/.gnupg directory.
122 'pw-file=s' => \
$pw_file, # Read password out of this file.
123 'agent' => \
$use_gpg_agent, # Use gpg-agent for passwords.
124 'Agent-info=s' => \
$gpg_agent_info, # Specify GnuPG agent connection
126 'Wipe' => \
$wipe_mode, # Securely delete unencrypted files.
127 'wipe-path=s' => \
$wipe_cmd, # Path to wipe command.
128 'wipe-interactive' => \
$wipe_interactive, # Disable "wipe -I"
129 'wipe-cmdline=s' => \
$wipe_cmdline, # Specify wipe command line.
130 'Obfuscate-filenames' => \
$obfuscate_mode, # substitute real filenames
131 # with manufactured ones.
132 'obfuscate-map-file=s' => \
$obfuscate_map_filename, # path to mapping file.
133 'Force' => \
$force_mode, # Continue if files can't be deleted.
134 'overwrite-encrypted' => \
$overwrite_encrypted, # Overwrite encrypted files
135 # even if they exist.
136 'overwrite-decrypted' => \
$overwrite_decrypted, # Overwrite decrypted files
137 # even if they exist.
138 'Exclude=s' => \
$exclude_pat, # Exclude a pattern from encrypt/decrypt
140 'Exclude-from=s' => \
$exclude_file, # Exclude patterns in <file> from
141 # encrypt decrypt cycle.
142 'Include=s' => \
$include_pat, # Specify a pattern used to restrict
143 # encrypt/decrypt operation to.
144 'Include-from=s' => \
$include_file, # Specify a file of include patterns to
145 # restrict all encrypt/decrypt
147 'test-mode' => \
$test_and_exit, # Run encrypt -> decrypt test only and
149 'Trial-run' => \
$trial_run, # Don't modify any files; just show what
150 # would have happened.
151 'quiet' => \
$quiet, # Print as little as possible to
153 'Interactive' => \
$interactive_mode, # Query the user before encrypting/
154 # decrypting/deleting any files.
155 'Key-id=s' => \
$encrypt_user, # Specify encrypt/decrypt key
156 'Default-key' => \
$use_default_key, # Assume that default-key is set within
158 'Symmetric' => \
$symmetric_mode, # encrypt using symmetric cipher.
159 # (this option is not required to
160 # also decrypt, GnuPG handles
161 # that automatically).
162 'Plain-ascii' => \
$ascii_armor_mode, # Ascii armor mode (creates non-binary
164 'skip-test' => \
$skip_test_mode, # Skip encrypt -> decrypt test.
165 'no-recurse' => \
$norecurse, # Don't encrypt/decrypt files in
167 'no-delete' => \
$no_delete, # Don't delete files once they have
169 'no-password' => \
$cmdline_no_password, # Do not query for a password (only
170 # useful for when the gpg literally
172 'user-homedir=s' => \
$homedir, # Path to home directory.
173 'no-preserve-times' => \
$no_fs_times, # Don't preserve mtimes or atimes.
174 'verbose' => \
$verbose, # Verbose mode.
175 'Version' => \
$printver, # Print version
176 'help' => \
$help # Print help
178 &usage_and_exit
() if $help;
180 print "[+] gpgdir v$version (file revision: $rev_num)\n",
181 " by Michael Rash <mbr\@cipherdyne.org>\n"
182 and exit 0 if $printver;
184 if ($symmetric_mode and ($use_gpg_agent or $gpg_agent_info)) {
185 die "[*] gpg-agent incompatible with --Symmetric mode";
188 if ($encrypt_dir and $overwrite_decrypted) {
189 die "[*] The -e and --overwrite-decrypted options are incompatible.";
191 if ($decrypt_dir and $overwrite_encrypted) {
192 die "[*] The -d and --overwrite-encrypted options are incompatible.";
196 unless (-e
$wipe_cmd) {
197 die "[*] Can't find wipe command at: $wipe_cmd,\n",
198 " use --wipe-path to specify path.";
200 unless (-e
$wipe_cmd) {
201 die "[*] Can't execute $wipe_cmd";
205 ### build up GnuPG options hash
207 %options = ('homedir' => $gpg_homedir);
211 'homedir' => $gpg_homedir
215 $options{'armor'} = 1 if $ascii_armor_mode;
217 ### get the path to the user's home directory
218 $homedir = &get_homedir
() unless $homedir;
220 unless ($symmetric_mode) {
221 if ($gpg_homedir) { ### specified on the command line with --gnupg-dir
222 unless ($gpg_homedir =~ /\.gnupg$/) {
223 die "[*] Must specify the path to a user .gnupg directory ",
224 "e.g. /home/username/.gnupg\n";
227 if (-d
"${homedir}/.gnupg") {
228 $gpg_homedir = "${homedir}/.gnupg";
231 unless (-d
$gpg_homedir) {
232 die "[*] GnuPG directory: ${homedir}/.gnupg does not exist. Please\n",
233 " create it by executing: \"gpg --gen-key\". Exiting.\n";
236 ### get the key identifier from ~/.gnupg
237 $encrypt_user = &get_key
() unless $encrypt_user or $use_default_key;
240 if ($decrypt_dir and $encrypt_dir) {
241 die "[*] You cannot encrypt and decrypt the same directory.\n";
245 unless ($decrypt_dir or $encrypt_dir or $test_and_exit) {
246 print "[*] Please specify -e <dir>, -d <dir>, or --test-mode\n";
250 ### exclude file pattern
251 push @exclude_patterns, $exclude_pat if $exclude_pat;
254 open P
, "< $exclude_file" or die "[*] Could not open file: $exclude_file";
257 for my $line (@lines) {
258 next unless $line =~ /\S/;
260 push @exclude_patterns, qr{$line};
264 ### include file pattern
265 push @include_patterns, $include_pat if $include_pat;
268 open P
, "< $include_file" or die "[*] Could not open file: $include_file";
271 for my $line (@lines) {
272 next unless $line =~ /\S/;
274 push @include_patterns, qr{$line};
281 } elsif ($decrypt_dir) {
287 die "[*] Directory does not exist: $dir" unless -e
$dir;
288 die "[*] Not a directory: $dir" unless -d
$dir;
291 ### don't need to test encrypt/decrypt ability if we are running
292 ### in --Trial-run mode.
293 $skip_test_mode = 1 if $trial_run;
295 my $initial_dir = cwd
or die "[*] Could not get CWD: $!";
297 if ($symmetric_mode) {
300 &get_password
() unless $encrypt_mode and $skip_test_mode;
305 } elsif ($dir !~ m
|^/|) {
306 $dir = $initial_dir . '/' . $dir;
308 $dir =~ s
|/$||; ### remove any trailing slash
310 ### run a test to make sure gpgdir and encrypt and decrypt a file
311 unless ($skip_test_mode) {
312 my $rv = &test_mode
();
313 exit $rv if $test_and_exit;
317 print "[+] Encrypting directory: $dir\n" unless $quiet;
319 print "[+] Decrypting directory: $dir\n" unless $quiet;
322 ### build a hash of file paths to work against
325 ### perform the gpg operation (encrypt/decrypt)
328 &obfuscated_mapping_files
() if $obfuscate_mode;
330 unless ($obfuscate_mode) {
331 if ($have_obfuscated_file) {
332 print "[-] Obfuscated filenames detected, try decrypting with -O.\n"
338 print "[+] Total number of files encrypted: " .
339 "$total_encrypted\n" unless $quiet;
341 print "[+] Total number of files decrypted: " .
342 "$total_decrypted\n" unless $quiet;
346 #==================== end main =====================
349 my ($in_file, $out_file, $del_flag) = @_;
351 my $gpg = GnuPG
::Interface
->new();
352 $gpg->options->hash_init(%options);
354 die "[*] Could not create new gpg object with ",
355 "homedir: $gpg_homedir" unless $gpg;
357 unless ($symmetric_mode or $use_default_key) {
358 $gpg->options->default_key($encrypt_user);
359 $gpg->options->push_recipients($encrypt_user);
362 my ($input_fh, $output_fh, $error_fh, $pw_fh, $status_fh) =
363 (IO
::File
->new($in_file),
364 IO
::File
->new("> $out_file"),
369 my $handles = GnuPG
::Handles
->new(
371 stdout
=> $output_fh,
373 passphrase
=> $pw_fh,
376 $handles->options('stdin')->{'direct'} = 1;
377 $handles->options('stdout')->{'direct'} = 1;
381 if ($use_gpg_agent or $gpg_agent_info) {
383 ### set environment explicitly if --Agent was specified
384 if ($gpg_agent_info) {
385 $ENV{'GPG_AGENT_INFO'} = $gpg_agent_info;
388 $pid = $gpg->encrypt('handles' => $handles,
389 'command_args' => [ qw( --use-agent ) ]);
392 if ($symmetric_mode) {
393 $pid = $gpg->encrypt_symmetrically('handles' => $handles);
395 $pid = $gpg->encrypt('handles' => $handles);
402 my @errors = <$error_fh>;
408 print if /bad\s+pass/;
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.";
427 die "[*] Created zero-size file: $out_file\n",
428 " Bad password? Try re-running with -v.";
436 my ($in_file, $out_file, $del_flag) = @_;
438 my $gpg = GnuPG
::Interface
->new();
439 $gpg->options->hash_init(%options);
441 die "[*] Could not create new gpg object with ",
442 "homedir: $gpg_homedir" unless $gpg;
444 unless ($symmetric_mode or $use_default_key) {
445 $gpg->options->default_key($encrypt_user);
446 $gpg->options->push_recipients($encrypt_user);
449 my ($input_fh, $output_fh, $error_fh, $pw_fh, $status_fh) =
450 (IO
::File
->new($in_file),
451 IO
::File
->new("> $out_file"),
456 my $handles = GnuPG
::Handles
->new(
458 stdout
=> $output_fh,
460 passphrase
=> $pw_fh,
463 $handles->options('stdin')->{'direct'} = 1;
464 $handles->options('stdout')->{'direct'} = 1;
468 if ($use_gpg_agent) {
469 $pid = $gpg->decrypt('handles' => $handles,
470 'command_args' => [ qw( --use-agent ) ]);
472 $pid = $gpg->decrypt('handles' => $handles);
478 my @errors = <$error_fh>;
484 print if /bad\s+pass/;
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.";
503 die "[*] Created zero-size file: $out_file\n",
504 " Bad password? Try re-running with -v.";
513 return if $no_delete;
514 return unless -e
$file;
519 $cmd .= " $wipe_cmdline ";
521 if ($wipe_interactive) {
529 print " Executing: $cmd\n";
540 my $msg = "[-] Could not delete file: $file\n";
542 print $msg unless $quiet;
544 die $msg unless $quiet;
550 sub gpg_operation
() {
552 ### sort by oldest to youngest mtime
553 FILE
: for my $file (sort
554 {$files{$a}{'mtime'} <=> $files{$b}{'mtime'}} keys %files) {
556 ### see if we have an exclusion pattern that implies
557 ### we should skip this file
558 if (@exclude_patterns and &exclude_file
($file)) {
559 print "[+] Skipping excluded file: $file\n"
560 if $verbose and not $quiet;
564 ### see if we have an inclusion pattern that implies
565 ### we should process this file
566 if (@include_patterns and not &include_file
($file)) {
567 print "[+] Skipping non-included file: $file\n"
568 if $verbose and not $quiet;
572 ### dir is always a full path
573 my ($dir, $filename) = ($file =~ m
|(.*)/(.*)|);
575 unless (chdir($dir)) {
576 print "[-] Could not chdir $dir, skipping.\n" unless $quiet;
580 my $mtime = $files{$file}{'mtime'};
581 my $atime = $files{$file}{'atime'};
585 my $encrypt_filename = "$filename.gpg";
587 if ($obfuscate_mode) {
589 unless (defined $obfuscate_ctrs{$dir}) {
591 ### create a new gpgdir mapping file for obfuscated file
592 ### names, but preserve any previously encrypted file
594 &handle_old_obfuscated_map_file
();
596 ### make obfuscated file names start at 1 for each
598 $obfuscate_ctrs{$dir} = 1;
601 $encrypt_filename = 'gpgdir_' . $$ . '_'
602 . $obfuscate_ctrs{$dir} . '.gpg';
605 if ($ascii_armor_mode) {
606 $encrypt_filename = "$filename.asc";
609 if (-e
$encrypt_filename and not $overwrite_encrypted) {
610 print "[-] Encrypted file $dir/$encrypt_filename already ",
611 "exists, skipping.\n" unless $quiet;
615 if ($interactive_mode) {
616 next FILE
unless (&query_yes_no
(
617 " Encrypt: $file ([y]/n)? ", $ACCEPT_YES_DEFAULT));
620 print "[+] Encrypting: $file\n" unless $quiet;
622 unless ($trial_run) {
624 &encrypt_file
($filename, $encrypt_filename,
625 $NO_DEL_SOURCE_FILE);
627 if (-e
$encrypt_filename && -s
$encrypt_filename != 0) {
628 ### set the atime and mtime to be the same as the
630 unless ($no_fs_times) {
631 if (defined $mtime and $mtime and
632 defined $atime and $atime) {
633 utime $atime, $mtime, $encrypt_filename;
636 ### only delete the original file if
637 ### the encrypted one exists
638 if ($wipe_mode and not $quiet) {
639 print " Securely deleting file: $file\n";
641 &delete_file
($filename);
643 if ($obfuscate_mode) {
645 ### record the original file name mapping
646 &append_obfuscated_mapping
($filename,
649 $obfuscate_ctrs{$dir}++;
655 print "[-] Could not encrypt file: $file\n" unless $quiet;
662 ### allow filenames with spaces
663 my $decrypt_filename = '';
664 if ($filename =~ /^(.+)\.gpg$/) {
665 $decrypt_filename = $1;
666 } elsif ($filename =~ /^(.+)\.asc$/) {
667 $decrypt_filename = $1;
670 if ($obfuscate_mode) {
672 &import_obfuscated_file_map
($dir)
673 unless defined $obfuscated_dirs{$dir};
675 if (defined $obfuscated_dirs{$dir}{$filename}) {
676 $decrypt_filename = $obfuscated_dirs{$dir}{$filename};
679 print "[-] Obfuscated file map does not exist for $filename in\n",
680 " $obfuscate_map_filename, skipping.\n";
685 if (not $force_mode and $file =~ /gpgdir_\d+_\d+.gpg/) {
686 ### be careful not to decrypt obfuscated file unless we
687 ### are running in -O mode. This ensures that the
688 ### original file names will be acquired from the
689 ### /some/dir/.gpgdir_map_file
690 $have_obfuscated_file = 1;
695 ### length() allows files named "0"
696 next FILE
unless length($decrypt_filename) > 0;
698 ### don't decrypt a file on top of a normal file of
700 if (-e
$decrypt_filename and not $overwrite_decrypted) {
701 print "[-] Decrypted file $dir/$decrypt_filename ",
702 "already exists. Skipping.\n" unless $quiet;
706 if ($interactive_mode) {
707 next FILE
unless (&query_yes_no
(
708 " Decrypt: $file ([y]/n)? ", $ACCEPT_YES_DEFAULT));
711 unless ($trial_run) {
713 print "[+] Decrypting: $dir/$filename\n" unless $quiet;
714 &decrypt_file
($filename, $decrypt_filename,
715 $NO_DEL_SOURCE_FILE);
717 if (-e
$decrypt_filename && -s
$decrypt_filename != 0) {
718 ### set the atime and mtime to be the same as the
720 unless ($no_fs_times) {
721 if (defined $mtime and $mtime and
722 defined $atime and $atime) {
723 utime $atime, $mtime, $decrypt_filename;
726 if ($wipe_mode and not $quiet) {
727 print " Securely deleting file: $file\n";
729 ### only delete the original encrypted
730 ### file if the decrypted one exists
731 &delete_file
($filename);
736 print "[-] Could not decrypt file: $file\n" unless $quiet;
742 print "\n" unless $quiet;
743 chdir $initial_dir or die "[*] Could not chdir: $initial_dir\n";
750 print "[+] Building file list...\n" unless $quiet;
752 opendir D
, $dir or die "[*] Could not open $dir: $!";
753 my @files = readdir D
;
756 for my $file (@files) {
757 next if $file eq '.';
758 next if $file eq '..';
759 &check_file_criteria
("$dir/$file");
762 ### get all files in all subdirectories
763 find
(\
&find_files
, $dir);
770 for my $pat (@exclude_patterns) {
771 if ($file =~ m
|$pat|) {
772 print "[+] Skipping $file (matches exclude pattern: $pat)\n"
773 if $verbose and not $quiet;
782 for my $pat (@include_patterns) {
783 if ($file =~ m
|$pat|) {
784 print "[+] Including $file (matches include pattern: $pat)\n"
785 if $verbose and not $quiet;
792 sub obfuscated_mapping_files
() {
796 $dirs_href = \
%obfuscate_ctrs;
798 $dirs_href = \
%obfuscated_dirs;
801 DIR
: for my $dir (keys %$dirs_href) {
802 unless (chdir($dir)) {
803 print "[-] Could not chdir $dir, skipping.\n" unless $quiet;
808 next DIR
unless -e
$obfuscate_map_filename;
809 ### encrypt the map file now that we have encrypted
811 print "[+] Encrypting mapping file: ",
812 "$dir/$obfuscate_map_filename\n" unless $quiet;
813 unless ($trial_run) {
814 &encrypt_file
($obfuscate_map_filename,
815 "$obfuscate_map_filename.gpg", $NO_DEL_SOURCE_FILE);
817 unlink $obfuscate_map_filename;
820 next DIR
unless -e
"$obfuscate_map_filename.gpg";
821 ### delete the map file since we have decrypted
823 print "[+] Decrypting mapping file: ",
824 "$dir/$obfuscate_map_filename.gpg\n" unless $quiet;
825 unless ($trial_run) {
826 &decrypt_file
("$obfuscate_map_filename.gpg",
827 $obfuscate_map_filename, $NO_DEL_SOURCE_FILE);
829 unlink "$obfuscate_map_filename.gpg";
836 sub handle_old_obfuscated_map_file
() {
837 return unless -e
"$obfuscate_map_filename.gpg";
839 &decrypt_file
("$obfuscate_map_filename.gpg",
840 $obfuscate_map_filename, $NO_DEL_SOURCE_FILE);
842 unlink "$obfuscate_map_filename.gpg";
844 my @existing_obfuscated_files = ();
846 open F
, "< $obfuscate_map_filename" or die "[*] Could not open ",
847 "$obfuscate_map_filename: $!";
849 if (/^\s*.*\s+(gpgdir_\d+_\d+.gpg)/) {
851 push @existing_obfuscated_files, $_;
857 if (@existing_obfuscated_files) {
858 ### there are some obfuscated files from a previous gpgdir
860 open G
, "> $obfuscate_map_filename" or die "[*] Could not open ",
861 "$obfuscate_map_filename: $!";
862 print G
for @existing_obfuscated_files;
868 sub append_obfuscated_mapping
() {
869 my ($filename, $encrypt_filename) = @_;
871 open G
, ">> $obfuscate_map_filename" or die "[*] Could not open ",
872 "$obfuscate_map_filename: $!";
873 print G
"$filename $encrypt_filename\n";
878 sub import_obfuscated_file_map
() {
881 $obfuscated_dirs{$dir} = {};
883 return unless -e
"$obfuscate_map_filename.gpg";
885 &decrypt_file
("$obfuscate_map_filename.gpg",
886 $obfuscate_map_filename, $NO_DEL_SOURCE_FILE);
888 open G
, "< $obfuscate_map_filename" or die "[*] Could not open ",
889 "$obfuscate_map_filename: $!";
891 if (/^\s*(.*)\s+(gpgdir_\d+_\d+.gpg)/) {
892 $obfuscated_dirs{$dir}{$2} = $1;
903 if (-e
'/etc/passwd') {
904 open P
, '< /etc/passwd' or
905 die "[*] Could not open /etc/passwd. Exiting.\n";
908 for my $line (@lines) {
909 ### mbr:x:222:222:Michael Rash:/home/mbr:/bin/bash
911 if ($line =~ /^(?:.*:){2}$uid:(?:.*:){2}(\S+):/) {
917 $homedir = $ENV{'HOME'} if defined $ENV{'HOME'};
919 die "[*] Could not determine home directory. Use the -u <homedir> option."
925 if (-e
"${homedir}/.gpgdirrc") {
926 open F
, "< ${homedir}/.gpgdirrc" or die "[*] Could not open ",
927 "${homedir}/.gpgdirrc. Exiting.\n";
931 for my $line (@lines) {
933 if ($line =~ /^\s*default_key/) {
934 ### prefer to use the default GnuPG key
935 $use_default_key = 1;
937 } elsif ($line =~ /^\s*use_key\s+(.*)$/) {
938 ### GnuPG accepts strings to match the key, so we don't
939 ### have to strictly require a key ID... just a string
940 ### that matches the key
945 "[*] Please edit ${homedir}/.gpgdirrc to include your gpg key identifier\n",
946 " (e.g. \"D4696445\"; see the output of \"gpg --list-keys\"), or use the\n",
947 " default GnuPG key defined in ~/.gnupg/options";
949 print "[+] Creating gpgdir rc file: $homedir/.gpgdirrc\n";
950 open F
, "> ${homedir}/.gpgdirrc" or die "[*] Could not open " .
951 "${homedir}/.gpgdirrc. Exiting.\n";
953 print F
<<_CONFIGRC_
;
954 # Config file for gpgdir.
956 # Set the key to use to encrypt files with "use_key <key>", e.g.
957 # "use_key D4696445". See "gpg --list-keys" for a list of keys on your
958 # GnuPG key ring. Alternatively, if you want gpgdir to always use the
959 # default key that is defined by the "default-key" variable in
960 # ~/.gnupg/options, then uncomment the "default_key" line below.
962 # Uncomment to use the GnuPG default key defined in ~/.gnupg/options:
965 # If you want to use a specific GnuPG key, Uncomment the next line and
966 # replace "KEYID" with your real key id:
972 "[*] Please edit $homedir/.gpgdirrc to include your gpg key identifier,\n",
973 " or use the default GnuPG key defined in ~/.gnupg/options. Exiting.\n";
978 my $file = $File::Find
::name
;
979 &check_file_criteria
($file);
983 sub check_file_criteria
() {
985 ### skip all links, zero size files, all hidden
986 ### files (includes .gnupg files), etc.
988 if (-e
$file and not -l
$file and -s
$file != 0
989 and $file !~ m
|/\
.|) {
991 if ($file =~ m
|\
.gpg
| or $file =~ m
|\
.asc
|) {
992 print "[-] Skipping encrypted file: $file\n" unless $quiet;
996 unless ($file =~ m
|\
.gpg
| or $file =~ m
|\
.asc
|) {
997 print "[-] Skipping unencrypted file: $file\n" unless $quiet;
1001 my ($atime, $mtime) = (stat($file))[8,9];
1002 $files{$file}{'atime'} = $atime;
1003 $files{$file}{'mtime'} = $mtime;
1005 print "[-] Skipping file: $file\n"
1006 if $verbose and not $quiet;
1011 sub get_password
() {
1013 ### this is only useful if the gpg key literally has no password
1014 ### (usually this is not the case, but gpgdir will support it if
1016 return if $cmdline_no_password;
1018 ### if we are using gpg-agent for passwords, then return
1019 return if $use_gpg_agent;
1022 open PW
, "< $pw_file" or die "[*] Could not open $pw_file: $!";
1027 print "[+] Executing: gpgdir @args_cp\n" unless $quiet;
1028 if ($symmetric_mode) {
1029 print " [Symmetric mode]\n" unless $quiet;
1031 if ($use_default_key) {
1032 print " Using default GnuPG key.\n" unless $quiet;
1034 print " Using GnuPG key: $encrypt_user\n" unless $quiet;
1037 if ($test_and_exit) {
1038 print " *** test_mode() ***\n" unless $quiet;
1040 if ($encrypt_mode) {
1041 print ' Enter password (for initial ' .
1042 "encrypt/decrypt test)\n" unless $quiet;
1044 my $msg = 'Password: ';
1045 ### get the password without echoing the chars back to the screen
1063 chdir $dir or die "[*] Could not chdir($dir): $!";
1065 my $test_file = "gpgdir_test.$$";
1066 print "[+] test_mode(): Encrypt/Decrypt test of $test_file\n"
1067 if (($test_and_exit or $verbose) and not $quiet);
1069 if (-e
$test_file) {
1070 &delete_file
($test_file) or
1071 die "[*] test_mode(): Could not remove $test_file: $!";
1073 if (-e
"$test_file.gpg") {
1074 &delete_file
("$test_file.gpg") or
1075 die "[*] test_mode(): Could not remove $test_file.gpg: $!";
1078 open G
, "> $test_file" or
1079 die "[*] test_mode(): Could not create $test_file: $!";
1080 print G
"gpgdir test\n";
1083 if (-e
$test_file) {
1084 print "[+] test_mode(): Created $test_file\n"
1085 if (($test_and_exit or $verbose) and not $quiet);
1087 die "[*] test_mode(): Could not create $test_file\n";
1090 &encrypt_file
($test_file, "${test_file}.gpg", $DEL_SOURCE_FILE);
1092 if (-e
"$test_file.gpg" and (-s
$test_file != 0)) {
1093 print "[+] test_mode(): Successful encrypt of $test_file\n"
1094 if (($test_and_exit or $verbose) and not $quiet);
1095 &delete_file
($test_file) if -e
$test_file;
1097 die "[*] test_mode(): not encrypt $test_file (try adding -v).\n";
1100 &decrypt_file
("${test_file}.gpg", $test_file, $DEL_SOURCE_FILE);
1102 if (-e
$test_file and (-s
$test_file != 0)) {
1103 print "[+] test_mode(): Successful decrypt of $test_file\n"
1104 if (($test_and_exit or $verbose) and not $quiet);
1106 die "[*] test_mode(): Could not decrypt $test_file.gpg ",
1107 "(try adding -v).\n";
1109 open F
, "< $test_file" or
1110 die "[*] test_mode(): Could not open $test_file: $!";
1114 if (defined $line and $line =~ /\S/) {
1116 if ($line eq 'gpgdir test') {
1117 print "[+] test_mode(): Decrypted content matches original.\n",
1118 "[+] test_mode(): Success!\n\n"
1119 if (($test_and_exit or $verbose) and not $quiet);
1121 die "[*] test_mode(): Decrypted content does not match ",
1122 "original (try adding -v).";
1125 die "[*] test_mode(): Fail (try adding -v).\n";
1127 &delete_file
($test_file) if -e
$test_file;
1128 &delete_file
("$test_file.gpg") if -e
"$test_file.gpg";
1130 chdir $initial_dir or die "[*] Could not chdir($initial_dir)";
1135 sub query_yes_no
() {
1136 my ($msg, $style) = @_;
1138 while ($ans ne 'y' and $ans ne 'n') {
1141 if ($style == $ACCEPT_YES_DEFAULT) {
1142 return 1 if $ans eq "\n";
1143 } elsif ($style == $ACCEPT_NO_DEFAULT) {
1144 return 0 if $ans eq "\n";
1148 return 1 if $ans eq 'y';
1152 sub usage_and_exit
() {
1155 gpgdir
; Recursive direction encryption
and decryption with GnuPG
1157 [+] Version
: $version (file revision
: $rev_num)
1158 By Michael Rash
(mbr\
@cipherdyne.org
)
1159 URL
: http
://www
.cipherdyne
.org
/gpgdir/
1161 Usage
: gpgdir
-e
|-d
<directory
> [options
]
1164 -e
, --encrypt
<directory
> - Encrypt
<directory
> and all of its
1166 -d
, --decrypt
<directory
> - Decrypt
<directory
> and all of its
1168 -a
, --agent
- Acquire password information from a
1169 running instance of gpg
-agent
.
1170 -A
, --Agent
-info
<info
> - Specify the value
for the GPG_AGENT_INFO
1171 environment variable as returned by
1172 'gpg-agent --daemon'.
1173 -g
, --gnupg
-dir
<dir
> - Specify a path to a
.gnupg directory
for
1174 gpg
keys (the
default is
~/.gnupg
if this
1175 option is
not used
).
1176 -p
, --pw
-file
<file
> - Read password
in from
<file
>.
1177 -s
, --skip
-test
- Skip encrypt
-> decrypt test
.
1178 -t
, --test
-mode
- Run encrypt
-> decrypt test
and exit.
1179 -T
, --Trial
-run
- Show what filesystem actions would take
1180 place without actually doing them
.
1181 -P
, --Plain
-ascii
- Ascii armor mode
(creates non
-binary
1183 --Interactive
- Query the user before encrypting
,
1184 decrypting
, or deleting any files
.
1185 --Exclude
<pattern
> - Skip all filenames that match
<pattern
>.
1186 --Exclude
-from
<file
> - Skip all filenames that match any pattern
1187 contained within
<file
>.
1188 --Include
<pattern
> - Include only those filenames that match
1190 --Include
-from
<file
> - Include only those filenames that match a
1191 pattern contained within
<file
>.
1192 -K
, --Key
-id
<id
> - Specify GnuPG key ID
, or key
-matching
1193 string
. This overrides the use_key value
1195 -D
, --Default
-key
- Use the key that GnuPG defines as the
1196 default (i
.e
. the key that is specified
1197 by the
default-key option
in
1199 -O
, --Obfuscate
-filenames
- Substitute all real filenames
in a
1200 directory with manufactured ones
(the
1201 original filenames are preserved
in a
1202 mapping file
and restored
when the
1203 directory is decrypted
).
1204 --obfuscate
-map_file
<file
> - Specify path to obfuscated mapping file
1206 -F
, --Force
- Continue to run even
if files cannot be
1207 deleted
(because of permissions problems
1209 --overwrite
-encrypted
- Overwrite encrypted files even
if a
1210 previous
<file
>.gpg file already
exists.
1211 --overwrite
-decrypted
- Overwrite decrypted files even
if the
1212 previous unencrypted file already
exists.
1213 -q
, --quiet
- Print as little to the screen as possible
1214 -W
, --Wipe
- Use the
'wipe' command to securely
delete
1215 unencrypted copies of files after they
1216 have been encrypted
.
1217 --wipe
-path
<path
> - Specify path to the wipe command
.
1218 --wipe
-interactive
- Force interactive mode with the wipe
1220 --wipe
-cmdline
<args
> - Manually specify command line arguments
1221 to the wipe command
.
1222 --no-recurse
- Don
't recursively encrypt/decrypt
1224 --no-delete - Don't
delete original unencrypted files
.
1225 --no-preserve
-times - Don
't preserve original mtime and atime
1226 values on encrypted/decrypted files.
1227 --no-password - Assume the gpg key has no password at all
1228 (this is not common).
1229 -u, --user-homedir <dir> - Path to home directory.
1230 -v, --verbose - Run in verbose mode.
1231 -V, --Version - print version.
1232 -h, --help - print help.