soppakirja.pl
#!/usr/bin/perl -w
use strict;
use Fcntl ':mode';
use Getopt::Long;
#
# $Id: soppakirja.pl,v 1.12 2004-12-04 15:59:15+02 qvr Exp qvr $
#
# This will try to keep your passwords etc safe.
# You'll need a working pgp installation and a pgp private key
# with a good password.
#
# Run soppakirja.pl and it will create its home directory and a default config file.
# Edit the config to your liking and run soppakirja.pl again, remember
# to save after editing the file and voila, your passwords and whatnot are safe.
#
# If you don't trust root, don't use this. If you think your server is compromised,
# don't use this. If you don't understand this, dont use this.
# You should not leave this running on a screen when you dont need it, as that
# kinda defeats the whole point of this. While this is running, the only thing
# keeping your passwords safe are directory permissions.
#
# Making backups of the encrypted file (and your keyrings) on to a
# physically different location is a smart move.
#
# If an error occurs, the script will do its best not to leave open password
# file hanging around.
#
# copyright 2004 matti@hiljanen.com
#
# User settings are now read from the config,
# end-user should not edit anything here
my $workdir = $ENV{HOME} . "/.soppakirja";
my ($force_encrypt, $help, $verbose, $extraconf);
my (@configs, $decrypted, $encrypt_to, @editor, $encrypted, @decrypt, @encrypt, @edit, @ls);
our ($opt_workdir, $opt_decrypted, $opt_encrypt_to);
GetOptions(
"help|h" => \$help,
"verbose|v" => \$verbose,
"config|C=s" => \$extraconf,
"workdir=s",
"decrypted=s",
"encrypt-to=s" => \$opt_encrypt_to,
"force-encrypt" => \$force_encrypt);
$workdir = $opt_workdir if ($opt_workdir);
print '$Id: soppakirja.pl,v 1.12 2004-12-04 15:59:15+02 qvr Exp qvr $' . "\n";
if ($help) {
print <<EOF;
Usage: $0 [OPTION]...
Options:
(no options) open soppakirja normally
--force-encrypt encrypt an open (unencrypted) soppakirja
--workdir=DIR the working directory, needs secure permissions
--encrypt-to=EMAIL the encryption key to use
--decrypted=FILE the unencrypted soppakirja, under workdir
-C, --config=FILE config file to read
-h, --help this help
EOF
exit 0;
}
# config parsing
my $configured = 0;
push(@configs, "$extraconf") if $extraconf;
push(@configs, "$workdir/config.pl");
push(@configs, $ENV{HOME} . "/.soppakirja/config.pl");
push(@configs, $ENV{HOME} . "/.soppakirjarc");
foreach my $config (@configs) {
next if $configured;
if (-f $config && -r $config && -s $config) {
eval(`cat $config`);
die "FATAL configuration error: $@" if $@;
print "config loaded from $config\n";
$configured = $config;
}
}
$decrypted = $opt_decrypted if ($opt_decrypted);
$workdir = $opt_workdir if ($opt_workdir);
$encrypt_to = $opt_encrypt_to if ($opt_encrypt_to);
if (!$configured) {
print "no config found, creating it for you...\n";
my $file;
if (-d $workdir && -w $workdir) {
$file = "$workdir/config.pl";
} else {
$file = $ENV{HOME} . "/.soppakirjarc";
}
open(CONFIG, "> $file")
or die "FATAL: couldn't write config: $@!\n";
print CONFIG <<EOF;
### This is the configuration file for soppakirja, the friendly password manager ###
# \$workdir = \$ENV{HOME} . "/.soppakirja";
\$decrypted = "soppakirja"; # the secret file, this is under \$workdir
\$encrypt_to = ''; # your gpg encrypting key (aka. email address)
# if you change this, make sure the editor doesn't use swap files and such
\@editor = ("vim", "-n");
EOF
close(CONFIG);
print "done. please edit $file and then try again\n";
print "exiting...\n";
exit 1;
} else { # let's check for config validity
if ($workdir && $decrypted && $encrypt_to && @editor) {
if ($decrypted =~ /[^a-z]/i) {
print "FATAL: bad characters in \$decrypted! Please edit config file $configured.\nExiting...\n";
exit 1;
}
$decrypted = "$workdir/$decrypted";
$encrypted = $decrypted . ".asc";
@decrypt = ("gpg", "--decrypt-files", "$encrypted");
@encrypt = ("gpg", "-a", "-v", "-r", "$encrypt_to", ,"-o", "$encrypted", "--encrypt", "$decrypted");
@edit = (@editor, "$decrypted");
@ls = ("ls", "-l", "$workdir");
#print "soppakirja is at $decrypted\nwe will encrypt to $encrypt_to\nand editor is $editor[0]\n";
#exit 1;
} else {
print "config file loaded but not it's not valid, please edit $configured\n";
print "exiting...\n";
exit 1;
}
}
if (!-d $workdir) {
if (mkdir $workdir, 0700) {
print "$workdir created\n";
} else {
print <<EOF;
could not create $workdir
create it manually first
exiting...
EOF
exit 1;
}
}
my $dirmode = (stat($workdir))[2];
if ($dirmode & S_IRWXO || $dirmode & S_IRWXG) {
print <<EOF;
$workdir is not secure!
chmod 0700 $workdir and try again
exiting...
EOF
exit 1;
}
if ($force_encrypt) {
system(@encrypt) == 0
or die "FATAL: encrypting failed, aborting!";
unlink($decrypted) == 1
or die "FATAL: unlink failed: $!!";
print "Soppakirja is now locked.\n";
exit 0;
}
if (-e $decrypted) {
print <<EOF;
soppakirja already open!
close the other running process OR encrypt it with $0 --force-encrypt
exiting...
EOF
exit 1;
}
sub try {
my @cmd = @_;
system(@cmd) == 0
or cleanup(@cmd);
return;
}
sub cleanup {
my @cmd = @_;
print STDERR "ERROR: '@cmd' failed! Trying to pick up the pieces...\n";
if (-e $decrypted) {
print STDERR "Decrypted file still open! not good...\n";
system(@encrypt) == 0
or die "FATAL: encrypting failed, aborting!";
unlink($decrypted) == 1
or die "FATAL: unlink failed: $!!";
}
print STDERR "Cleanup done (seemingly successfully). Exiting...\n";
system(@ls);
exit 1;
}
if (-e $encrypted) {
try(@decrypt);
unlink($encrypted) == 1
or cleanup("unlink($encrypted)");
} else {
print "$encrypted does not exist, creating a new soppakirja\n";
print "CTRL-C to cancel, ENTER to continue\n";
my $foo; read(STDIN,$foo,1);
}
try(@edit);
try("clear");
try(@encrypt);
unlink($decrypted) == 1
or cleanup("unlink($decrypted)");
print "Soppakirja is now locked.\n";