#!/usr/bin/perl # # (c) 2008 spd-developer-team # kumbach # scabrera # cchrischh # GPL use strict; # strict handling use warnings; # show warnings use Getopt::Long; # used to make -parameter possible Getopt::Long::Configure ("bundling"); # you can combine parameters with it. -avx = -a -v -x use GnuPG::Interface; # GPG Interface for perl use IO::Handle; # module to open filehandles use IO::File; # needed to open files directly use Switch; # module to handle switches use File::Temp qw/ tempfile /; # needed to create secure temporary files use File::Copy; # needed to copy files #use Term::ReadKey; <-- not needed right now (you can turn echo off etc.) # maybe we shall use it to save the passwort through the whole runtime of the program # in a Handle, that we do not have to retype the passwort for signing a once opened file use Term::ANSIColor qw(:constants); # make color possible $Term::ANSIColor::AUTORESET = 1; # autoreset colorscheme after each \n use Digest::MD5::File qw(file_md5_hex); # use Mail::Sender; #use open ':utf8'; # all input and output strings shall be utf8 strings #can not be used because of destroying the "--edit" procedure. umlauts are displayed mutated my $HOME = $ENV{'HOME'}; my ($fh, $MKTEMP) = tempfile( UNLINK => 1 ); my ($output_file_fh, $output_file) = tempfile(); my $SPD_DIR = "$HOME/.spd"; my $EDITOR = "vi"; my $VERSION = "0.1"; my $SYSTEM_CONFIG = "/etc/spd/spd.conf"; my $MAIL_DEBUG = "$HOME/.spd/mail_log.txt"; # Procedure to check the configuration file and load the settings # got this configuration parser from http://www.patshaping.de/hilfen_ta/codeschnipsel/perl-configparser.htm sub parse_config($) { my $file = shift; local *CF; open(CF,'<'.$file) || die "Open $file: $!\n"; read(CF, my $data, -s $file); close(CF) || die "could not close $file. that shouldn't happen\n"; my @lines = split(/\015\012|\012|\015/,$data); my $config = {}; my $count = 0; foreach my $line(@lines) { $count++; next if($line =~ /^\s*#/); next if($line !~ /^\s*\S+\s*=.*$/); my ($key,$value) = split(/=/,$line,2); # Remove whitespaces at the beginning and at the end $key =~ s/^\s+//g; $key =~ s/\s+$//g; $value =~ s/^\s+//g; $value =~ s/\s+$//g; die "Configuration option '$key' defined twice in line $count of configuration file '$file'" if($config->{$key}); $config->{$key} = $value; } return $config; } # Procedure to get strings splitted on whitespace sub split_string($) { my $names = shift; my @name_array = ""; if ( $names ) { @name_array = split(/\s+/, $names); } return @name_array; } # Generation wizzard for a config-file sub config_wizard { my $answers; my $shared_users; if ( !$main::CONFIG_FILE ){ our $CONFIG_FILE = "$SPD_DIR/spd.conf"; } if ( $main::CONFIG_FILE eq "$SPD_DIR/spd.conf" ){ if ( !-e "$SPD_DIR" ){ mkdir("$SPD_DIR",0755) || die "cannot mkdir $SPD_DIR: $!\n"; } } open(CONFIGFILE,">$main::CONFIG_FILE") || die "cannot create $main::CONFIG_FILE: $!\n"; # generating default header print CONFIGFILE "## Configfile generated with configuration wizzard\n"; print CONFIGFILE "#\n"; print CONFIGFILE "## What is your NAME and GPG_ID?(needed):\n"; print CONFIGFILE "#\n"; # getting your name and GPG_ID print "What is your Name?(shouldn't have any spaces in it):"; $answers = ; chomp($answers); print CONFIGFILE "YOUR_ID = " . $answers . "\n"; print CONFIGFILE "#\n"; print CONFIGFILE $answers; print CONFIGFILE " = "; print "Which GPG_ID do you have?"; $answers = ; print CONFIGFILE $answers; print CONFIGFILE "#\n"; print "-------------------------------------------\n"; # getting users your sharing your passfile with print "Do you share your passfile with any other users?(y/n)"; my $yes_no = ; chomp($yes_no); print CONFIGFILE "## Which users do you share your passfile with? (optional)\n"; print CONFIGFILE "#\n"; # generating dummy if you do not share with anybody if ( $yes_no ne "y" ){ print CONFIGFILE "# USERNAME1 = GPG_ID\n"; print CONFIGFILE "# USERNAME2 = GPG_ID\n"; $shared_users = "USERNAME1 USERNAME2"; print CONFIGFILE "#\n"; print CONFIGFILE "# "; } else { $shared_users = ""; } # else generating real users while ( $yes_no eq "y" ){ print "What is the name of the person your sharing your file with\n(shouldn't have any spaces in it):"; $answers = ; chomp($answers); print CONFIGFILE $answers; print CONFIGFILE " = "; $shared_users = $shared_users . $answers . " "; print "What is the GPG_ID of $answers?"; $answers = ; print CONFIGFILE $answers; print "Do you want to add any other person?(y/n)"; $yes_no = ; chomp($yes_no); } print CONFIGFILE "TRUSTED_IDS = " . $shared_users . "\n"; print CONFIGFILE "#\n"; print "-------------------------------------------\n"; # getting the passfile right now print "Where is your passfile located?(absolute path):"; $answers = ; print CONFIGFILE "# Specify your PASSFILE here(needed)\n"; print CONFIGFILE "#\n"; print CONFIGFILE "PASSFILE = " . $answers; print CONFIGFILE "#\n"; print "-------------------------------------------\n"; # asking the shared_passfile thing print "Do you want to use a shared passfile?\nyou can have a shared passfile beside your local one.\nthat means to specify a networkdrive or anything like this(y/n)"; $yes_no = ; chomp $yes_no; print CONFIGFILE "## Specify a Shared PASSFILE here (optional)\n"; print CONFIGFILE "#\n"; # generating shared passfile or dummy one if ( $yes_no eq "y" ){ print "Where is the SHARD_PASSFILE located?:"; $answers = ; print CONFIGFILE "SHARED_PASSFILE = " . $answers; } else { print CONFIGFILE "# SHARED_PASSFILE = /mnt/network_drive/.shared/spd_data.gpg\n"; } print CONFIGFILE "#\n"; print "-------------------------------------------\n"; # Following the color-section print "Do you want to configure the password-column right now?\nThis entry is printed red on red that nobody looking your shoulder can read it.(y/n)"; $yes_no = ; chomp($yes_no); print CONFIGFILE "## define here which lines should be password [red on red] (that nobody which looks on your screen can read it)\n"; print CONFIGFILE "## you can add multiple words here with a whitespace between(if you have whitespaces in your line use double colon :: as whitespace).\n"; print CONFIGFILE "#\n"; if ( $yes_no eq "y" ){ print "What are your password-columns?\nJust write with whitespaces in between if using more than one column\n"; $answers = ; print CONFIGFILE "PASSWORD = " . $answers; } else { print CONFIGFILE "# PASSWORD = Password\n"; } print CONFIGFILE "#\n"; print "Do you want to add columns which shall be printed YELLOW?(y/n)"; $yes_no = ; chomp($yes_no); print CONFIGFILE "## here you can define Colors for your lines\n"; print CONFIGFILE "## available statements are \"YELLOW, RED, BLUE, GREEN\"\n"; print CONFIGFILE "#\n"; if ( $yes_no eq "y" ){ print "What are your yellow colored columns?\nJust write with whitespaces in between if using more than one column\n"; $answers = ; print CONFIGFILE "YELLOW = " . $answers; } else { print CONFIGFILE "# YELLOW = ID\n"; } print CONFIGFILE "#\n"; print "Do you want to add columns which shall be printed BLUE?(y/n)"; $yes_no = ; chomp($yes_no); if ( $yes_no eq "y" ){ print "What are your blue colored columns?\nJust write with whitespaces in between if using more than one column\n"; $answers = ; print CONFIGFILE "BLUE = " . $answers; } else { print CONFIGFILE "# BLUE = username\n"; } print CONFIGFILE "#\n"; print "Do you want to add columns which shall be printed GREEN?(y/n)"; $yes_no = ; chomp($yes_no); if ( $yes_no eq "y" ){ print "What are your green colored columns?\nJust write with whitespaces in between if using more than one column\n"; $answers = ; print CONFIGFILE "GREEN = " . $answers; } else { print CONFIGFILE "# GREEN = accesslink\n"; } print CONFIGFILE "#\n"; print "Do you want to add columns which shall be printed RED?(y/n)"; $yes_no = ; chomp($yes_no); if ( $yes_no eq "y" ){ print "What are your red colored columns?\nJust write with whitespaces in between if using more than one column\n"; $answers = ; print CONFIGFILE "RED = " . $answers; } else { print CONFIGFILE "# RED = accessmethod\n"; } print CONFIGFILE "#\n"; print "-------------------------------------------\n"; # editor used to edit the passfile print "Do you want to specify an Editor right now??\nusing vi if not(y/n)"; $yes_no = ; chomp($yes_no); print CONFIGFILE "## Which editor do you use to edit files? (optional)\n"; print CONFIGFILE "#\n"; # generating dummy if not specifying this if ( $yes_no eq "y" ){ print "Specify the editor you want to use right now:\n"; $answers = ; chomp($answers); print CONFIGFILE "EDITOR = \""; print CONFIGFILE "$answers"; print CONFIGFILE "\"\n"; } else { print CONFIGFILE "# EDITOR = vi\n"; } print CONFIGFILE "#\n"; print "-------------------------------------------\n"; # The Mailing section print "Do you want to have mailing support?\nThat means that you passfile gets mailed out on any changes to specified adresses(y/n)"; $yes_no = ; chomp($yes_no); print CONFIGFILE "# Following are the Mailing options (optional)\n"; print CONFIGFILE "#\n"; print CONFIGFILE "## Who shall receive your passfile? (give a comma seperated list)\n"; print CONFIGFILE "#\n"; if ( $yes_no eq "y" ){ print "Who shall receive your passfile?Just write a comma seperated list.\n"; $answers = ; print CONFIGFILE "MAIL_RECEIVERS = " . $answers; } else { print CONFIGFILE "# MAIL_RECEIVERS = user\@domain.tld\n"; } print CONFIGFILE "#\n"; print CONFIGFILE "## What SMTP-Relay shall i use?\n"; print CONFIGFILE "#\n"; if ( $yes_no eq "y" ){ print "What SMTP-Relay do you use?Just type your mailserver here.\n"; $answers = ; print CONFIGFILE "MAIL_SMTP = " . $answers; } else { print CONFIGFILE "# MAIL_SMTP = mail.domain.tld\n"; } print CONFIGFILE "#\n"; print CONFIGFILE "## What Adress do you want to send from?\n"; print CONFIGFILE "#\n"; if ( $yes_no eq "y" ){ print "What Adress do you want to send from?\n"; $answers = ; print CONFIGFILE "MAIL_FROM = " . $answers; } else { print CONFIGFILE "# MAIL_FROM = myname\@domain.tld\n"; } print CONFIGFILE "#\n"; print CONFIGFILE "## The Message of the Mail\n"; print CONFIGFILE "#\n"; if ( $yes_no eq "y" ){ print "Which Message shall this mail have?\n"; $answers = ; print CONFIGFILE "MAIL_MSG = " . $answers; } else { print CONFIGFILE "# MAIL_MSG = attached is the new encrypted password file."; } print CONFIGFILE "#\n"; print CONFIGFILE "## The Mail Subject?\n"; print CONFIGFILE "#\n"; if ( $yes_no eq "y" ){ print "Last but not least the Subject of these Mails:\n"; $answers = ; print CONFIGFILE "MAIL_SUBJECT = " . $answers; } else { print CONFIGFILE "# MAIL_SUBJECT = [UPDATE] spd_data.gpg"; } close(CONFIGFILE) || die "can't close $main::CONFIG_FILE: $!\n"; } # Generate a sample config-file sub default_config { local *CONFIGFILE; if ( -e "$SPD_DIR" && -d "$SPD_DIR" ){ open(CONFIGFILE,">$main::CONFIG_FILE") || die "cannot create $main::CONFIG_FILE: $!\n"; print CONFIGFILE "# Here are all the default-values # ## What is your NAME and GPG-ID?(needed) ## # MYNAME = GPG_ID # # YOUR_ID = MYNAME # ## Which users do you share your passfile with? (optional) # # USERNAME1 = GPG_ID # USERNAME2 = GPG_ID # # TRUSTED_IDS = USERNAME1 USERNAME2 # ## Specify your PASSFILE here(needed) # # PASSFILE = $SPD_DIR/spd_data.gpg # ## Specify a Shared PASSFILE here (optional) # # SHARED_PASSFILE = $HOME/.shared/spd_data.gpg # ## define here which lines should be password [red on red] (that nobody which looks on your screen can read it) ## you can add multiple words here with a whitespace between(if you have whitespaces in your line use double colon :: as whitespace). # # PASSWORD = Password # ## here you can define Colors for your lines ## # available statements are \"YELLOW, RED, BLUE, GREEN\" # # YELLOW = ID # # BLUE = Hostname # # GREEN = Protocol # # RED = Accessmethod Accesslink Username # ## Which editor do you use to edit files? (optional) # # EDITOR = vim # ## Who shall receive yor passfile (give a comma seperated list)? (optional) # #MAIL_RECEIVERS = test\@fq.dn, user\@fq.dn # ## What smtp-relay shall i use? (required if MAIL_RECEIVERS are set) # #MAIL_SMTP = smtp.fq.dn # ## What Adress do you want to send from? (required if MAIL_RECEIVERS are set) # #MAIL_FROM = myname\@fq.dn # ## The Message of the Mail (required if MAIL_RECEIVERS are set) # #MAIL_MSG = attached is the new encrypted passwordfile # ## The Mail Subject? (required if MAIL_RECEIVERS are set) # #MAIL_SUBJECT = spd_data.gpg #"; close(CONFIGFILE) || die "can't close $main::CONFIG_FILE: $!\n"; } else { mkdir("$SPD_DIR",0755) || die "cannot mkdir $SPD_DIR: $!\n"; default_config(); } } # Function to check if all needed variables are set and get them ready to use sub check_config { my $config; # check if configfile is present if ( !$main::CONFIG_FILE ){ our $CONFIG_FILE = "$SPD_DIR/spd.conf"; if ( -e $CONFIG_FILE ){ $config=parse_config($CONFIG_FILE); } elsif ( -e $main::SYSTEM_CONFIG ){ $config=parse_config($main::SYSTEM_CONFIG); } else { print "CONFIG FILE NOT FOUND!\n"; print "Do you want to create one with the wizard (w) or generate a default one (d) ?"; my $answer = ; chomp($answer); if ( $answer eq "w" ) { config_wizard(); } else { print "GENERATING A SAMPLE TO $CONFIG_FILE\n"; default_config(); } exit 0; } } else { if ( !-f $main::CONFIG_FILE ){ die "FILE \"$main::CONFIG_FILE\" NOT FOUND!" } } # is the EDITOR-variable defined? if not let it be "vi" if ( $config->{EDITOR} ){ $EDITOR = $config->{EDITOR}; } # is a shared PASSFILE defined? and readable? if ( $config->{SHARED_PASSFILE} && !$main::LOCAL ){ our $SHARED_PASSFILE = $config->{SHARED_PASSFILE}; if ( !-r $SHARED_PASSFILE && !$main::CREATE ) { die "PASSFILE $SHARED_PASSFILE NOT FOUND OR NOT READABLE!\nForgot --create?\nForgot --local?\n"; } elsif ( !-e $SHARED_PASSFILE && $main::CREATE ) { open(my $PASSFILE,'>'.$SHARED_PASSFILE) || die "CANNOT CREATE $SHARED_PASSFILE: $!\nMissing Directory??\n"; close($PASSFILE) || die "could not close $SHARED_PASSFILE. THAT SHOULDN'T HAPPEN.\n"; } } # is PASSFILE defined? and readable? if ( !$main::PASSFILE ){ if ( $config->{PASSFILE} ){ our $PASSFILE = $config->{PASSFILE}; if ( !-r $main::PASSFILE && !$main::CREATE ) { die "PASSFILE $main::PASSFILE NOT FOUND OR NOT READABLE!\nForgot --create?\n"; } elsif ( !-e $main::PASSFILE && $main::CREATE ) { open(PASSFILE,'>'.$main::PASSFILE) || die "CANNOT CREATE $main::PASSFILE: $!\n"; close PASSFILE || die "could not close $main::PASSFILE. that shouldn't happen.\n"; } } else { die "PASSFILE NOT DEFINED!\n"; } } else { if ( !-r $main::PASSFILE && !$main::CREATE ) { die "PASSFILE $main::PASSFILE NOT FOUND OR NOT READABLE!\nFORGOT --create?" } elsif ( !-e $main::PASSFILE && $main::CREATE ) { open(PASSFILE,'>'.$main::PASSFILE) || die "CANNOT CREATE $main::PASSFILE: $!\n"; close PASSFILE || die "Could not close $main::PASSFILE. that shouldn't happen.\n"; } } # is YOUR_ID defined? if ( $config->{YOUR_ID} ) { our $YOUR_NAME = $config->{YOUR_ID}; } else { die "YOUR_ID NOT SET! CHECK YOUR CONFIG-FILE\n"; } if ( $config->{$main::YOUR_NAME} ) { our $YOUR_ID = $config->{$config->{YOUR_ID}}; } else { die "$main::YOUR_NAME NOT DEFINED!\n"; } # get the gpg-key of TRUSTED_ID if ( $config->{TRUSTED_IDS} ){ my @name = split_string($config->{TRUSTED_IDS}); my $elements = @name; our @IDS; for ( my $i=0; $i<$elements; $i++) { if ( $config->{$name[$i]} ) { $IDS[$i] = "$config->{$name[$i]}"; } else { die "$name[$i] NOT DEFINED! CHECK YOUR CONFIGFILE"; } } } # get the lines which should be colored if ( $config->{RED} ){ our $RED = $config->{RED}; } if ( $config->{YELLOW} ){ our $YELLOW = $config->{YELLOW}; } if ( $config->{BLUE} ){ our $BLUE = $config->{BLUE}; } if ( $config->{GREEN} ){ our $GREEN = $config->{GREEN}; } if ($config->{PASSWORD} ){ our $PASSWORDLINE = $config->{PASSWORD}; } # check if Mailsettings are given if ( $config->{MAIL_RECEIVERS} ){ our $MAIL_RECEIVERS = $config->{MAIL_RECEIVERS}; if ( $config->{MAIL_SMTP} ){ our $MAIL_SMTP = $config->{MAIL_SMTP}; if ( $config->{MAIL_FROM} ){ our $MAIL_FROM = $config->{MAIL_FROM}; if ( $config->{MAIL_MSG} ){ our $MAIL_MSG = $config->{MAIL_MSG}; } else { die "MAIL RECEIVERS GIVEN BUT MISSING MESSAGE!\n"; } if ( $config->{MAIL_SUBJECT} ){ our $MAIL_SUBJECT = $config->{MAIL_SUBJECT}; } else { die "MAIL RECEIVERS GIVEN BUT MISSING SUBJECT!\n"; } } else { die "MAIL RECEIVERS GIVE BUT MISSING MAIL_FROM!\n"; } } else { die "MAIL_RECEIVERS GIVEN BUT MISSING SMTP-RELAY!\n"; } } } # decrypt the passfile sub decrypt_passfile { my $file = shift; my $gnupg = GnuPG::Interface->new(); # load object # $gnupg->options->hash_init(armor => 1); # set armor enabled (not needed here) my $output = IO::Handle->new(); # output Handle my $infile = IO::File->new( "<$file" ); # open $PASSFILE for reading my $handles = GnuPG::Handles->new( stdin => $infile, stdout => $output, stderr => "/dev/null"); $handles->options( 'stdin' )->{direct} = 1; $gnupg->passphrase( my $passphrase ); # Load the passphrase from STDIN my $pid = $gnupg->decrypt( handles => $handles ); # start the decryption close $infile; # close $cipher_file my @DECRYPTED = <$output>; # insert output in array "@result" close $output; # close $output waitpid $pid, 0; # clean up the finished GnuPG process return @DECRYPTED; # return the decrypted passfile } # does string contain any of array? sub string_equals_array { my $string = shift; my @array = split_string($_[0]); if ( $string ) { $string =~ s/\s+$//g; # remove whitespaces out of string if ( $array[0] ne "" ) { foreach my $array_element (@array) { $array_element =~ s/::/ /g; if ($string =~ /^$array_element+$/) {return 1;}} } return 0; } else { return 0; } } # does string contain any of string? sub string_contains_string { my $string = shift; my $string2 = shift; if ( !$string2 ) { return 1} elsif ($string =~ /$string2/i) {return 1;} else { return 0; } } # function to get max length of string sub get_max_length { my $length = shift; my @string = @_; # get max length of "DESCRIPTION" foreach my $part_of_string ( @string ) { my $length_string = length $part_of_string; if ( $length < $length_string ) { $length = $length_string; } } return $length; } # function to make string or array equal to max length sub make_strings_equal { my $length = shift; my @string = @_; my $quantity_string = @string; # make them all to one length for ( my $i = 0; $i < $quantity_string; $i++ ) { my $length_string = length $string[$i]; my $missing = $length - $length_string; for ( my $x = 0; $x < $missing; $x++ ) { $string[$i] = $string[$i] . " "; } } return @string; } # send searchresults to STDOUT sub print_results { my $file = shift; my @PLAINPASSFILE = decrypt_passfile($file); my @temp_id; my @id; my $id_string = "ID"; my @RESULTSET; my @length_columns; my $max_desclength = 0; if ( !@PLAINPASSFILE ) { die "$file has no DATA?\nTyped Passphrase three times wrong?\n"; } my @Description = split(/\t/,$PLAINPASSFILE[0]); #save Description shift ( @PLAINPASSFILE ); # delete first Element of Array my $QUANTITY_Desc = @Description; # save Quantity of Array Description $Description[$QUANTITY_Desc -1] =~ s/\r//; # to get those windows linefeeds away chomp($Description[$QUANTITY_Desc -1]); # needed to delete the \n my $quantity_plainpassfile = @PLAINPASSFILE; my $id_counter = 0; my $searchword = shift(@_); for ( my $i = 0; $i < $quantity_plainpassfile; $i++ ) { my $is_in = string_contains_string($PLAINPASSFILE[$i], $searchword); my $is_in2 = string_contains_string(($i+1), $searchword); if ( ($is_in) || ($is_in2) ) { $temp_id[$id_counter] = ($i+1); $RESULTSET[$id_counter] = $PLAINPASSFILE[$i]; $id_counter++; } } if ( $_[0] ) { foreach $searchword ( @_ ) { @PLAINPASSFILE = @RESULTSET; @RESULTSET = (); @id = (); $id_counter = 0; $quantity_plainpassfile = @PLAINPASSFILE; for ( my $i = 0; $i < $quantity_plainpassfile; $i++ ) { my $is_in = string_contains_string($PLAINPASSFILE[$i], $searchword); my $is_in2 = string_contains_string($temp_id[$i], $searchword); if ( ($is_in) || ($is_in2) ) { $id[$id_counter] = ($temp_id[$i]); $RESULTSET[$id_counter] = $PLAINPASSFILE[$i]; $id_counter++; } } @temp_id = @id; } } else { @id = @temp_id; } # split each line (separated by tab) and write it to STDOUT my $line_counter=1; $id_counter = 0; if ( $main::WIDE ) { ############################################################################################## #### the following is absolutely nasty...don't know if there is any way other doing it....#### ############################################################################################## my $passwordline; my $red; my $yellow; my $blue; my $green; # check length of description and write to length array for ( my $i = 0; $i < $QUANTITY_Desc; $i++ ) { $length_columns[$i] = 0; $length_columns[$i] = get_max_length($length_columns[$i],$Description[$i]); } # check the length if there is any longer than the one from description my $quantity_resultset = @RESULTSET; for ( my $i = 0; $i < $quantity_resultset; $i++ ) { my @result = split(/\t/,$RESULTSET[$i]); my $quantity_result = @result; $result[$quantity_result -1] =~ s/\r//; # to get those windows linefeeds away chomp($result[$quantity_result -1]); # delete \n $line_counter++; if ( $QUANTITY_Desc == $quantity_result ) { for ( my $x = 0; $x < $quantity_result; $x++ ) { $length_columns[$x] = get_max_length($length_columns[$x],$result[$x]); } } else { die "ERROR - Quantity of description does not match quantity of results in line $line_counter\nof your datafile, there are $quantity_result instead of $QUANTITY_Desc items, which results in an ERROR"; } } # check which columns should be colored for ( my $i = 0; $i < $quantity_resultset; $i++ ) { if ( string_equals_array($Description[$i],$main::PASSWORDLINE) ) { $passwordline = $i; } elsif ( string_equals_array($Description[$i],$main::RED) ) { $red = $i; } elsif ( string_equals_array($Description[$i],$main::YELLOW) ){ $yellow = $i; } elsif ( string_equals_array($Description[$i],$main::BLUE) ){ $blue = $i; } elsif ( string_equals_array($Description[$i],$main::GREEN) ){ $green = $i; } } # print Description in the right length print "$id_string\t"; for ( my $i = 0; $i < $QUANTITY_Desc; $i++ ) { my @return = make_strings_equal($length_columns[$i],$Description[$i]); if ( $i < $QUANTITY_Desc-1 ) { print "@return\t"; } else { print "@return\n"; } } # adjust length of Resultset for ( my $i = 0; $i < $quantity_resultset; $i++ ) { my @result = split(/\t/,$RESULTSET[$i]); my $quantity_result = @result; $result[$quantity_result -1] =~ s/\r//; # to get those windows linefeeds away chomp($result[$quantity_result -1]); # delete \n for ( my $x = 0; $x < $quantity_result; $x++ ) { my @return = make_strings_equal($length_columns[$x],$result[$x]); $result[$x] = "@return"; } $RESULTSET[$i] = join("\t",@result); } # print Resultset for ( my $i = 0; $i < $quantity_resultset; $i++ ) { my @result = split(/\t/,$RESULTSET[$i]); my $quantity_result = @result; $result[$quantity_result -1]=~ s/\r//; # remove windows linefeed if ( string_equals_array($id_string,$main::RED) ) { print BOLD RED "$id[$i]"; print "\t"; } elsif ( string_equals_array($id_string,$main::YELLOW) ){ print BOLD YELLOW "$id[$i]"; print "\t"; } elsif ( string_equals_array($id_string,$main::BLUE) ){ print BOLD BLUE "$id[$i]"; print "\t"; } elsif ( string_equals_array($id_string,$main::GREEN) ){ print GREEN BOLD "$id[$i]"; print "\t"; } else { print BOLD "$id[$i]"; print "\t"; } chomp($result[$quantity_result -1]); # delete \n for ( my $x = 0; $x < ($quantity_result-1); $x++ ) { if ( $passwordline && $passwordline eq $x ) { print RED ON_RED "$result[$x]\t"; } elsif ( $red && $red eq $x ) { print BOLD RED "$result[$x]\t"; } elsif ( $yellow && $yellow eq $x ) { print BOLD YELLOW "$result[$x]\t"; } elsif ( $blue && $blue eq $x ){ print BOLD BLUE "$result[$x]\t"; } elsif ( $green && $green eq $x ){ print GREEN BOLD "$result[$x]\t"; } else { print BOLD "$result[$x]\t"; } } if ( $passwordline && $passwordline eq ($quantity_result-1) ) { print RED ON_RED "$result[$quantity_result -1]\n"; } elsif ( $red && $red eq ($quantity_result-1) ) { print BOLD RED "$result[$quantity_result -1]\n"; } elsif ( $yellow && $yellow eq ($quantity_result-1) ) { print BOLD YELLOW "$result[$quantity_result -1]\n"; } elsif ( $blue && $blue eq ($quantity_result-1) ){ print BOLD BLUE "$result[$quantity_result -1]\n"; } elsif ( $green && $green eq ($quantity_result-1) ){ print GREEN BOLD "$result[$quantity_result -1]\n"; } else { print BOLD "$result[$quantity_result -1]\n"; } } } else { # we shall norm the description-output before that we do not get shifted output # $max_desclength = get_max_length("0",@Description); @Description = make_strings_equal($max_desclength,@Description); # make ID also the same length my $length_desc = length $id_string; my $missing = $max_desclength - $length_desc; for ( my $x = 0; $x < $missing; $x++ ) { $id_string = $id_string . " "; } foreach my $line (@RESULTSET){ my @result = split(/\t/,$line); my $QUANTITY_result = @result; $result[$QUANTITY_result -1] =~ s/\r//; # to get those windows linefeeds away chomp($result[$QUANTITY_result -1]); # delete \n $line_counter++; if ( $QUANTITY_Desc == $QUANTITY_result ) { print "$id_string : "; if ( string_equals_array($id_string,$main::RED) ) { print BOLD RED "$id[$id_counter]"; print "\n"; } elsif ( string_equals_array($id_string,$main::YELLOW) ){ print BOLD YELLOW "$id[$id_counter]"; print "\n"; } elsif ( string_equals_array($id_string,$main::BLUE) ){ print BOLD BLUE "$id[$id_counter]"; print "\n"; } elsif ( string_equals_array($id_string,$main::GREEN) ){ print GREEN BOLD "$id[$id_counter]"; print "\n"; } else { print BOLD "$id[$id_counter]"; print "\n"; } for ( my $i = 0; $i < $QUANTITY_Desc; $i++ ) { print "$Description[$i] : "; if ( string_equals_array($Description[$i],$main::PASSWORDLINE) ) { print RED ON_RED "$result[$i]"; print "\n"; } elsif ( string_equals_array($Description[$i],$main::RED) ) { print BOLD RED "$result[$i]"; print "\n"; } elsif ( string_equals_array($Description[$i],$main::YELLOW) ){ print BOLD YELLOW "$result[$i]"; print "\n"; } elsif ( string_equals_array($Description[$i],$main::BLUE) ){ print BOLD BLUE "$result[$i]"; print "\n"; } elsif ( string_equals_array($Description[$i],$main::GREEN) ){ print GREEN BOLD "$result[$i]"; print "\n"; } else { print BOLD "$result[$i]"; print "\n"; } } $id_counter++; } else { die "ERROR - Quantity of description does not match quantity of results in line $line_counter\nof your datafile, there are $QUANTITY_result instead of $QUANTITY_Desc items, which results in an ERROR"; } print "\n"; } } } # sub check_sign cannot verify signature until it is decrypted # { # my $gnupg = GnuPG::Interface->new(); # load object # my $infile = IO::File->new( "<$main::PASSFILE" ); # my $output = IO::Handle->new(); # # my $handles = GnuPG::Handles->new( stdin => $infile, # stdout => $output); # # $handles->options( 'stdin' )->{direct} = 1; # # my $pid = $gnupg->verify( handles => $handles ); # # close $infile; # # my @signature = <$output>; # close $output; # print "@signature\n"; # # waitpid $pid, 0; # clean up the finished GnuPG process # die "all done!\n"; # } # encrypt given File to $OUTFILE and move it to $PASSFILE sub encrypt_file { my $input_file = shift; my $outfile = shift; my $gnupg = GnuPG::Interface->new(); # load object # We'll let the standard error of GnuPG pass through # to our own standard error, by not creating # a stderr-part of the $handles object. my $infile = IO::File->new( "$input_file" ); my $handles = GnuPG::Handles->new( stdin => $infile, stdout => $output_file_fh); $handles->options( 'stdin' )->{direct} = 1; # set option to directly use the filehandles $handles->options( 'stdout' )->{direct} = 1; # think this is needed when using files $gnupg->options->default_key ( $main::YOUR_ID ); # set default id here (if you have multiple ids you need that) $gnupg->options->push_recipients ( $main::YOUR_ID ); # set own-id to encrypt file if ( @main::IDS ) { foreach my $ID ( @main::IDS ) { $gnupg->options->push_recipients ( $ID ); # set all the other ids } } # this sets up the communication # Note that the recipients were specified earlier # in the 'options' data member of the $gnupg object. my $pid = $gnupg->sign_and_encrypt( handles => $handles ); # this closes the communication channel, # indicating we are done close $infile; close $output_file_fh; waitpid $pid, 0; # clean up the finished GnuPG process if ( $? == 0 ) { move($output_file, $outfile) || die "WARNING!! File $output_file cannot be moved to $outfile.\n$outfile not writeable?\n"; print "seems to me that everything worked fine. Passfile encrypted.\n"; } else { die "something went wrong, encryption stopped. hope you did not lose any changes?!?"; } } # encrypt given array to $OUTFILE and move it to $PASSFILE sub encrypt_array { my $outfile = shift; my @input_array = @_; my $gnupg = GnuPG::Interface->new(); # load object my $input = IO::Handle->new(); # We'll let the standard error of GnuPG pass through # to our own standard error, by not creating # a stderr-part of the $handles object. my $handles = GnuPG::Handles->new( stdin => $input, stdout => $output_file_fh); $handles->options( 'stdout' )->{direct} = 1; # think this is needed when using files $gnupg->options->default_key ( $main::YOUR_ID ); # set default id here (if you have multiple ids you need that) $gnupg->options->push_recipients ( $main::YOUR_ID ); # set own-id to encrypt file if ( @main::IDS ) { foreach my $ID ( @main::IDS ) { $gnupg->options->push_recipients ( $ID ); # set all the other ids } } # this sets up the communication # Note that the recipients were specified earlier # in the 'options' data member of the $gnupg object. my $pid = $gnupg->sign_and_encrypt( handles => $handles ); print $input @input_array; # this closes the communication channel, # indicating we are done close $input; close $output_file_fh; waitpid $pid, 0; # clean up the finished GnuPG process if ( $? == 0 ) { move($output_file, $outfile) || die "WARNING!! File $output_file cannot be moved to $outfile.\n$outfile not writeable?\n"; print "seems to me that everything worked fine. Passfile encrypted.\n"; } else { die "something went wrong, encryption stopped. hope you did not lose any changes?!?"; } } # function to join a given array to file sub join_array_to_file { my $file = shift; my @first_array = @_; my @second_array = decrypt_passfile($file); my @diff_array; my $diff_counter = 0; my $is_equal = 0; my $quantity_first_array = @first_array; my $quantity_second_array = @second_array; for ( my $i = 0; $i < $quantity_first_array; $i++ ) { for ( my $x = 0; $x < $quantity_second_array; $x++ ) { if ( $first_array[$i] eq $second_array[$x] ) { $is_equal = 1; last; } else { $diff_array[$diff_counter] = $first_array[$i]; } } if ( $is_equal ) { $is_equal = 0; } else { $diff_counter++; } } my @result_array = (@second_array,@diff_array); return @result_array; } # check if the edited file is ok sub check_quantity { my $file = shift; open(my $filehandle,'<'.$file) || die "Cannot open $file: $! that shouldn't happen\n"; my @passarray = <$filehandle>; close($filehandle) || die "Cannot close $file ?!?!? WTF that shouldn happen\n"; my @checkfile = @passarray; my $counter = 1; my $max_desclength = 0; my @Description = split(/\t/,$checkfile[0]); #save Description shift ( @checkfile ); # delete first Element of Array my $QUANTITY_Desc = @Description; # save Quantity of Array Description my @match = @checkfile; # get max length of "DESCRIPTION" foreach my $desc ( @Description ) { my $length_desc = length $desc; if ( $max_desclength < $length_desc ) { $max_desclength = $length_desc; } } foreach my $line (@match){ $counter++; my @result = split(/\t/,$line); my $QUANTITY_result = @result; if ( $QUANTITY_Desc != $QUANTITY_result ) { print "ERROR - Quantity of description does not match quantity of results in line $counter\nof your datafile, there are $QUANTITY_result instead of $QUANTITY_Desc items, which results in an ERROR\n"; return 1; } } return 0; } # procedure to edit the file with your editor sub edit_file { my $errorcode = 1; my $passfile = shift; my @plainpassfile = @_; my $answer = ""; open(my $mktemp_fh,'>'.$MKTEMP) || die "Open $MKTEMP: $! that shouldn't happen\n"; print $mktemp_fh @plainpassfile; close($mktemp_fh) || die "cannot close $MKTEMP. WTF?? that shouldn't happen\n"; my $md5sum_before_passfile = file_md5_hex($passfile); my $md5sum_before_tempfile = file_md5_hex($MKTEMP); while ( $errorcode == 1 ) { system("$EDITOR $MKTEMP"); $errorcode = check_quantity($MKTEMP); if ( $errorcode == 1 ) { print "Would you like to go back editing this?(y/n)"; my $input = ; chomp($input); if ( $input eq "n" ) { $errorcode = 0; } } } my $md5sum_after_tempfile = file_md5_hex($MKTEMP); my $md5sum_after_passfile = file_md5_hex($passfile); if ( $md5sum_before_passfile eq $md5sum_after_passfile ) { if ( $md5sum_before_tempfile ne $md5sum_after_tempfile ) { encrypt_file($MKTEMP,$passfile); send_passfile($passfile); } } else { while ( $answer ne "y" && $answer ne "n" ) { print "File has been changed while you were adding entries.\nMaybe someone used --force?\nDo you want to join you changes in?(y/n)\n"; $answer = ; chomp($answer); if ( $answer eq "y" ) { open(my $mktemp_fh,'<'.$MKTEMP) || die "Open $MKTEMP: $! that shouldn't happen\n"; @plainpassfile = <$mktemp_fh>; close($mktemp_fh) || die "cannot close $MKTEMP. that shouldn't happen\n"; @plainpassfile = join_array_to_file($passfile, @plainpassfile); encrypt_array($passfile, @plainpassfile); send_passfile($passfile); } elsif ( $answer eq "n" ) { print "Did nothing. Hope you did not lose any changes?!?\n"; } else { print "not a valid answer, please try again.\n"; $answer = ""; } } } } sub send_passfile { my $passfile = shift; if ( $main::MAIL_RECEIVERS ) { print "Sending Mail to $main::MAIL_RECEIVERS\n"; open my $DEBUG, "> $MAIL_DEBUG" || die "CANNOT OPEN MAIL_LOG $MAIL_DEBUG"; my $sender = new Mail::Sender ( { from => "$main::MAIL_FROM", smtp => "$main::MAIL_SMTP", debug => $DEBUG, debug_level => '1' } ); $sender->MailFile ( { to => "$main::MAIL_RECEIVERS", subject => "$main::MAIL_SUBJECT", msg => "$main::MAIL_MSG", file => "$passfile" } ); print "emails are sent out.\ncheck spd_debug.log ($MAIL_DEBUG) for any failures\n"; close $DEBUG; } else { return 0; } } sub compare_passfiles { my $first_passfile = shift; my $second_passfile = shift; my $md5sum_first_passfile = file_md5_hex($first_passfile); my $md5sum_second_passfile = file_md5_hex($second_passfile); if ( $md5sum_first_passfile ne $md5sum_second_passfile ) { print "$first_passfile does not match $second_passfile what would you like to do?\n"; print "a) overwrite $second_passfile with $first_passfile\n"; print "b) overwrite $first_passfile with $second_passfile\n"; print "c) do nothing at all\n"; my $selection = ; chomp($selection); switch ($selection) { case "a" { copy($second_passfile, "$second_passfile.bak") || print "Could not make a copy of $second_passfile!\n"; copy($first_passfile, $second_passfile) || die "Could not copy $second_passfile to $first_passfile. FAILED!\n$first_passfile not writeable?\n"; print "PASSFILE copied.\nBackup is $second_passfile.bak\nPress Enter to continue..."; my $buffer = ; } case "b" { copy($first_passfile, "$first_passfile.bak") || print "Could not backup $first_passfile\n"; copy($second_passfile, $first_passfile) || die "Could not copy $first_passfile to $second_passfile, FAILED!\n$second_passfile not writeable?\n"; print "PASSFILE copied.\nBackup is $first_passfile.bak\nPress Enter to continue..."; my $buffer = ; } case "c" { print "Did nothing.\n" } else { print "OPTION unknown. Did nothing.\n" } } } } # delete a whole column sub delete_column { my $file = shift; my $searchcolumn = shift; my $notfound = 0; my @PLAINPASSFILE = decrypt_passfile($file); if ( !@PLAINPASSFILE ) { die "$file has no DATA?\nTyped Passphrase three times wrong?\n"; } my @Description = split(/\t/,$PLAINPASSFILE[0]); #save Description my $QUANTITY_Desc = @Description; # save Quantity of Array Description my $quantity_plainpassfile = @PLAINPASSFILE; if ($searchcolumn =~ /^[0-9]*$/) { print "Sie wollen also die Spalte Nr. $searchcolumn löschen?(y/n)"; my $answer = ; chomp($answer); if ( $answer eq "y" ) { for ( my $i = 0; $i < $quantity_plainpassfile; $i++ ){ my $line = $PLAINPASSFILE[$i]; my @columns = split(/\t/,$line); delete $columns[$searchcolumn-1]; $line = $columns[0]; my $quantity_columns = @columns; if ( $quantity_columns <= 2 ) { $notfound = 1; } if ( $quantity_columns >= ($searchcolumn-1) ) { # searchcolumn-1 because if deleting last column if ( $searchcolumn == 1 ) { shift(@columns); $line = $columns[0]; $quantity_columns = @columns; } for ( my $y = 1; $y < $quantity_columns-1; $y++ ){ if ( $y != ($searchcolumn-1)) { $line = $line . "\t" . $columns[$y]; } } chomp($columns[$quantity_columns-1]); # you're wonderingy why i $line = $line . "\t" . $columns[$quantity_columns-1] . "\n"; # first delete it and then append it? $PLAINPASSFILE[$i] = $line; # what if deleting the last column? } else { $notfound = 1; } } if ( !$notfound ) { open(my $MKTEMP_fh,'>'.$MKTEMP) || die "Open $MKTEMP: $! that shouldn't happen\n"; print $MKTEMP_fh @PLAINPASSFILE; close($MKTEMP_fh) || die "cannot close $MKTEMP. WTF?? that shouldn't happen\n"; encrypt_file($MKTEMP,$file); } } else { print "ok, just did nothing...\n"; } } else { print "Sie wollen also die Spalte löschen die $searchcolumn enthält?(y/n)"; my $answer = ; my $counter = 0; chomp($answer); $notfound = 1; if ( $answer eq "y" ) { foreach my $desccolumn ( @Description ) { $counter++; if ( grep (/$searchcolumn/i, $desccolumn) ) { # search for matching patterns $notfound = 0; print "match in column $counter\n"; print "Are you sure to delete column nr. $counter?(y/n)"; $answer = ; chomp($answer); if ( $answer eq "y" ) { for ( my $i = 0; $i < $quantity_plainpassfile; $i++ ){ my $line = $PLAINPASSFILE[$i]; my @columns = split(/\t/,$line); delete $columns[$counter-1]; my $quantity_columns = @columns; if ( $quantity_columns <= 2 ) { $notfound = 1; } if ( $quantity_columns >= ($counter-1) ) { # counter-1 because if deleting last column if ( $counter == 1 ) { shift(@columns); $line = $columns[0]; $quantity_columns = @columns; } $line = $columns[0]; for ( my $y = 1; $y < $quantity_columns-1; $y++ ){ if ( $y != ($counter-1) ) { $line = $line . "\t" . $columns[$y]; } } chomp($columns[$quantity_columns-1]); $line = $line . "\t" . $columns[$quantity_columns-1] . "\n"; $PLAINPASSFILE[$i] = $line; } else { $notfound = 1; } } if ( !$notfound ) { open(my $MKTEMP_fh,'>'.$MKTEMP) || die "Open $MKTEMP: $! that shouldn't happen\n"; print $MKTEMP_fh @PLAINPASSFILE; close($MKTEMP_fh) || die "cannot close $MKTEMP. WTF?? that shouldn't happen\n"; encrypt_file($MKTEMP,$file); } } else { print "ok, just did nothing...\n"; } } } } else { print "ok, just did nothing...\n"; } } if ( $notfound ) { print "Sorry, could not delete column.\ncolumn not found or quantity das not match $file.\nIs your column-count > 2?\n"; } } # add a line to @plainpassfile sub add_line { my $file = shift; my @plainpassfile = decrypt_passfile($file); my $input; my $line; my $wanna_add = 1; my $answer = ""; if ( !@plainpassfile ) { die "$file has no DATA?\nTyped Passphrase three times wrong?\n"; } my @description = split(/\t/,$plainpassfile[0]); #save Description chomp(@description); my $description_length = @description; if ( $description_length < 3 ) { print "You cannot use this feature while your column count is less than 3\n"; } else { print "Now you can add entries to your passfile\n"; my $md5sum_before_adding = file_md5_hex($file); while ( $wanna_add ) { print "$description[0] :"; $input = ; chomp($input); $line = $input; for ( my $i = 1; $i < ($description_length-1); $i++ ){ print "$description[$i] :"; $input = ; chomp($input); $line = $line . "\t" . $input; } $description[($description_length-1)] =~ s/\r//; # to get those windows linefeeds away print "$description[($description_length-1)] :"; $line = $line . "\t" . ; push(@plainpassfile,$line); print "do you want to add another entry?(y/n)"; my $decision = ; chomp($decision); if ( $decision ne "y" ) { $wanna_add = 0; } } my $md5sum_after_adding = file_md5_hex($file); if ( $md5sum_before_adding eq $md5sum_after_adding ) { encrypt_array($file, @plainpassfile); send_passfile($file); } else { while ( $answer ne "y" && $answer ne "n" ) { print "File has been changed while you were adding entries.\nMaybe someone used --force?\nDo you want to join you changes in?(y/n)\n"; $answer = ; chomp($answer); if ( $answer eq "y" ) { @plainpassfile = join_array_to_file($file, @plainpassfile); encrypt_array($file, @plainpassfile); send_passfile($file); } elsif ( $answer eq "n" ) { print "Did nothing. Hope you did not lose any changes?!?\n"; } else { print "not a valid answer, please try again.\n"; $answer = ""; } } } } } sub adding { if ( !$main::SHARED_PASSFILE || $main::LOCAL ) { add_line($main::PASSFILE); } else { if ( -e "$main::SHARED_PASSFILE" ) { if ( -e "$main::SHARED_PASSFILE.lock" && !$main::FORCE ) { open (my $lockfile,"<$main::SHARED_PASSFILE.lock") || die "COULD NOT OPEN LOCKFILE $main::SHARED_PASSFILE.lock: $!. THAT SHOULDN'T HAPPEN!"; my $current_user = <$lockfile>; close($lockfile) || die "COULD NOT CLOSE LOCKFILE $main::SHARED_PASSFILE.lock: $!. THAT SHOULDN'T HAPPEN!"; print "You cannot edit $main::SHARED_PASSFILE as it is currently processed by $current_user\ntry --force if you really want to edit it (changes maybe lost)\n"; } else { if ( $main::FORCE ) { if ( -e "$main::SHARED_PASSFILE.lock" ) { unlink("$main::SHARED_PASSFILE.lock"); } } open (my $lockfile,">$main::SHARED_PASSFILE.lock") || die "COULD NOT OPEN LOCKFILE $main::SHARED_PASSFILE.lock for writing: $!.\nDoing this would be insecure\n"; print $lockfile "$main::YOUR_NAME (adding entries)"; close($lockfile) || die "COULD NOT CLOSE $main::SHARED_PASSFILE.lock after writing: $!.\n that REALLY shouldn't happen!\n"; add_line($main::SHARED_PASSFILE); unlink("$main::SHARED_PASSFILE.lock"); } } else { die "Shared Passfile $main::SHARED_PASSFILE is defined but not there.\nForgot --local?\n"; } } } sub editing { if ( !$main::SHARED_PASSFILE || $main::LOCAL) { edit_file($main::PASSFILE,decrypt_passfile($main::PASSFILE)); } else { if ( -e "$main::SHARED_PASSFILE.lock" && !$main::FORCE ) { open (my $lockfile,"<$main::SHARED_PASSFILE.lock") || die "COULD NOT OPEN LOCKFILE $main::SHARED_PASSFILE.lock: $!. THAT SHOULDN'T HAPPEN!"; my $current_user = <$lockfile>; close($lockfile) || die "COULD NOT CLOSE LOCKFILE $main::SHARED_PASSFILE.lock: $!. THAT SHOULDN'T HAPPEN!"; print "You cannot edit $main::SHARED_PASSFILE as it is currently processed by $current_user\ntry --force if you really want to edit it (changes maybe lost)\n"; } else { if ( $main::FORCE ) { if ( -e "$main::SHARED_PASSFILE.lock" ) { unlink("$main::SHARED_PASSFILE.lock"); } } open (my $lockfile,">$main::SHARED_PASSFILE.lock") || die "COULD NOT OPEN LOCKFILE $main::SHARED_PASSFILE.lock for writing: $!.\nDoing this would be insecure\n"; print $lockfile "$main::YOUR_NAME (editing)"; close($lockfile) || die "COULD NOT CLOSE $main::SHARED_PASSFILE.lock after writing: $!.\n that REALLY shouldn't happen!\n"; edit_file($main::SHARED_PASSFILE,decrypt_passfile($main::SHARED_PASSFILE)); unlink("$main::SHARED_PASSFILE.lock"); compare_passfiles($main::SHARED_PASSFILE, $main::PASSFILE); } } } sub importing { if ( !$main::SHARED_PASSFILE || $main::LOCAL) { encrypt_file($main::IMPORT,$main::PASSFILE); send_passfile($main::PASSFILE); } else { if ( -e "$main::SHARED_PASSFILE" ) { encrypt_file($main::IMPORT,$main::SHARED_PASSFILE); send_passfile($main::SHARED_PASSFILE); compare_passfiles($main::SHARED_PASSFILE, $main::PASSFILE); } else { die "Shared Passfile $main::SHARED_PASSFILE is defined but not there.\nForgot --local?\n"; } } } sub searching { if ( !$main::SHARED_PASSFILE || $main::LOCAL ) { print_results($main::PASSFILE, @ARGV); } else { if ( -e "$main::SHARED_PASSFILE" ) { compare_passfiles($main::SHARED_PASSFILE, $main::PASSFILE); print_results($main::SHARED_PASSFILE, @ARGV); } else { die "Shared Passfile $main::SHARED_PASSFILE is defined but not there.\nForgot --local?\n"; } } } sub deleting_column { my $delete_column = shift; if ( !$main::SHARED_PASSFILE || $main::LOCAL ) { delete_column($main::PASSFILE, $delete_column); } else { if ( -e "$main::SHARED_PASSFILE" ) { delete_column($main::SHARED_PASSFILE, $delete_column); } else { die "Shared Passfile $main::SHARED_PASSFILE is defined but not there.\nForgot --local?\n"; } } } # print helptext sub show_help { print "SPD - Simple Password Displayer - Version $VERSION\n\n"; print "Syntax: spd [options]|\n\n"; print "Options:\n"; print " --help | -h : display this wonderful help\n"; print " --import | -i : import a cleartext-file\n"; print " --config | -c : use configfile instead of the standard ones\n"; print " --passfile| -p : use passfile instead of the one set in spd.conf\n"; print " --local | -l : use local passfile instead of the shared one\n"; print " --force | -f : forcing some operations\n"; print " --wide | -w : give output in wide Format\n"; print " --create : to create the file (just to use with the -e flag)\n\n"; print "to handle the passfile:\n"; print " --delete-column : delete a column by number or word of the description\n"; print " --create-config : create a config using the wizard\n"; print " --edit | -e : edit the password-file with your favourite Editor\n"; print " --add | -a : interactive add a line\n\n"; print "With no parameters it will print out everything!\n"; exit 0; } # Main Methods close($fh) || die "Could not close $MKTEMP. THAT SHOULDN'T HAPPEN\n"; GetOptions ('help|h' => \my $help, 'version|v' => \my $version, 'config|c=s' => \my $conffile, 'passfile|p=s' => \my $passfile, 'local|l' => \our $LOCAL, 'force|f' => \our $FORCE, # 'checksign|cs' => \my $checksign, 'wide|w' => \our $WIDE, 'create' => \our $CREATE, 'edit|e' => \my $edit, 'delete-column=s' => \my $delete_column, 'create-config' => \my $create_config, 'import|i=s' => \our $IMPORT, 'add|a' => \my $add); if ( $help ){ show_help; } if ( $version ){ print "SPD - Simple Password Displayer - Version $VERSION\n\n"; exit 0; } if ( $conffile ){ our $CONFIG_FILE = $conffile } if ( $create_config ){ config_wizard(); exit 0; } if ( $passfile ){ our $PASSFILE = $passfile } # we need to check the config before doing any of the following check_config(); # if ( $checksign ){ # check_sign; # } if ( $delete_column ){ deleting_column($delete_column); exit 0; } elsif ( $add ){ adding(); exit 0; } elsif ( $edit ){ editing(); exit 0; } elsif ( $main::IMPORT ){ importing(); exit 0; } else { if ( $CREATE && !$edit ) { die "CANNOT CREATE WITHOUT EDIT"; } else { searching(); exit 0; } } # vim:tabstop=3