From a1937d716604efa52fc69170cd3ce1ac2f5211ed Mon Sep 17 00:00:00 2001 From: Rob van Son Date: Wed, 20 Jun 2012 16:00:44 +0200 Subject: [PATCH] Procedures for (re-)signing existing tickets and setting passwords --- CGIscriptor.html | 36 +++++++++++++++++++ CGIscriptor.pl | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 134 insertions(+), 6 deletions(-) diff --git a/CGIscriptor.html b/CGIscriptor.html index 7de2341..3be0c00 100644 --- a/CGIscriptor.html +++ b/CGIscriptor.html @@ -1697,6 +1697,42 @@ hash of some of the contents of the ticket with the server salt and CGIMasterKey is stored in each ticket.

+Creating a valid (hashed) password, encrypt it with the CGIMasterKey and +construct a signature of the ticket are non-trivial. This has to be redone +with every change of the ticket file or CGIMasterKey change. CGIscriptor +can do this from the command line with the command: +

+perl CGIscriptor.pl --managelogin salt=Private/.Passwords/SALT \
+  masterkey='Sherlock investigates oleander curry in Bath' \
+  password='There is no password like more password' \
+  admin
+
+CGIscriptor will exit after this command with the first option being +--managelogin. Options have the form: + +When the value of an option is a existing file path, the first line of +that file is used. Options are followed by one or more paths plus names +of existing ticket files. Each password option is only used for a single +ticket file. It is most definitely a bad idea to use a password that is +identical to an existing filepath, as the file will be read instead. Be +aware that the name of the file should be a cleaned up version of the +Username.This will not be checked. +

+

For the authentication and a change of password, the (old) password is used to "encrypt" a random one-time token or the new password, respectively. For authentication, decryption is not needed, so a secure diff --git a/CGIscriptor.pl b/CGIscriptor.pl index 12dfea1..df9ef2a 100755 --- a/CGIscriptor.pl +++ b/CGIscriptor.pl @@ -54,6 +54,7 @@ if(grep(/\-\-help/i, @ARGV)) # ENDOFPREHELPTEXT1 }; + # Configuration, copyright notice, and user manual follow the next # (Changes) section. # @@ -396,6 +397,34 @@ my %SETCOOKIELIST = (); # Expiration time (s): +3600 # + = relative time is absolute date-time # +# Manage login +# Set up a valid ticket from a given text file +# Use from command line. DO NOT USE ONLINE +# Watch out for passwords that get stored in the history file +# +# perl CGIscriptor.pl --managelogin [options] [files] +# Options: +# salt={file or saltvalue} +# masterkey={file or plaintext} +# newmasterkey={file or plaintext} +# password={file or palintext} +# +# Followed by one or more file names. +# Options can be interspersed between filenames, +# e.g., password='plaintext' +# Note that passwords are only used once! +# +if($ARGV[0] =~ /^\-\-managelogin/i) +{ + my @arguments = @ARGV; + shift(@arguments); + setup_ticket_file(@arguments); + # Should be run on the command line + exit; +}; + +# +# # Raw files must contain their own Content-type (xmr <- x-multipart-replace). # THIS IS A SUBSET OF THE FILES DEFINED IN $FilePattern $RawFilePattern = ".xmr"; @@ -3630,11 +3659,11 @@ sub write_ticket # ($ticketfile, $ticket, $salt [, $masterkey]) -> &%ticket EncryptTicketWithMasterKey($ticket, $salt, $masterkey); # Sign the new ticket - my @orderlist = ('Type', 'Username', 'IPaddress', 'AllowedPaths', 'DeniedPaths', + my @orderlist = ('Type', 'Username', 'Password', 'IPaddress', 'AllowedPaths', 'DeniedPaths', 'Expires', 'Capabilities', 'Salt', 'Session', 'Randomsalt', 'Date', 'Time', 'Signature', 'Key', 'Secretkey'); my @labellist = keys(%{$ticket}); - my $signature = SignTicketWithMasterkey($ticket, ""); + my $signature = SignTicketWithMasterkey($ticket, $salt, $masterkey); open(TICKET, ">$ticketfile") || die "$ticketfile: $!\n"; foreach my $label (@orderlist) { @@ -3756,6 +3785,68 @@ sub read_ticket # ($ticketfile [, $masterkey]) -> &%ticket return $ticket; }; +# Set up a valid ticket from a given text file +# Use from command line. DO NOT USE ONLINE +# Watch out for passwords that get stored in the history file +# +# perl CGIscriptor.pl --managelogin [options] [files] +# Options: +# salt={file or saltvalue} +# masterkey={file or plaintext} +# newmasterkey={file or plaintext} +# password={file or palintext} +# +# Followed by one or more file names. +# Options can be interspersed between filenames, +# e.g., password='plaintext' +# Note that passwords are only used once! +# +sub setup_ticket_file # (@ARGV) +{ + my %Settings = (); + foreach my $input (@_) + { + if($input =~ /^([\w]+)\=/) + { + my $name = lc($1); + my $value = $'; + chomp($value); + ; + if($value !~ m![^\w\.\~\/\:\-]! && $value !~ /^[\-\.]/ && -s "$value") + { + open(INPUTVALUE, "<$value") || die "$value: $!\n"; + $value = ; + chomp($value); + + }; + $value =~ s/(^\'([^\']*)\'$)/\1/g; + $value =~ s/(^\"([^\"]*)\"$)/\1/g; + $Settings{$name} = $value; + } + elsif($input !~ m![^\w\.\~\/\:\-]! && $input !~ /^[\-\.]/ && -s $input) + { + # We MUST have a salt + $Settings{'salt'} = $ticket->{'Salt'}->[0] unless $Settings{'salt'}; + + # Set the new masterkey to the old masterkey if there is no new masterkey + $Settings{'newmasterkey'} = $Settings{'masterkey'} unless exists($Settings{'newmasterkey'}); + + # Get the ticket + my $ticket = read_ticket($input, $Settings{'masterkey'}); + + # Set a new password from plaintext + $ticket->{'Salt'}->[0] = $Settings{'salt'} if $Settings{'salt'} && $Settings{'password'}; + set_password ($ticket, $Settings{'salt'}, $Settings{'password'}) if $Settings{'password'}; + + # Write the ticket back to file + write_ticket($input, $ticket, $Settings{'salt'}, $Settings{'newmasterkey'}); + + # A password is only used once + $Settings{'password'} = ""; + }; + }; +}; + # Add a signature from $masterkey to a ticket in the label $signlabel sub SignTicketWithMasterkey # ($ticket, $serversalt [, $masterkey, $signlabel]) -> $Signature { @@ -3807,12 +3898,13 @@ sub TicketSignature # ($ticket, $serversalt [, $masterkey]) -> $Signature }; # Decrypts a password list IN PLACE -sub DecryptTicketWithMasterKey # ($ticket, $serversalt) -> \@password_list +sub DecryptTicketWithMasterKey # ($ticket, $serversalt [, $masterkey]) -> \@password_list { my $ticket = shift || return 0; my $serversalt = shift || ""; + my $masterkey = shift || $ENV{'CGIMasterKey'}; - if($ENV{'CGIMasterKey'} && exists($ticket->{Password}) && $ticket->{Password}->[0]) + if($masterkey && exists($ticket->{Password}) && $ticket->{Password}->[0]) { # If the ServerSalt is not stored in the ticket, the SALT file has to be found if(exists($ticket->{Salt}) && $ticket->{Salt}->[0]) @@ -3822,7 +3914,7 @@ sub DecryptTicketWithMasterKey # ($ticket, $serversalt) -> \@password_list # Decrypt password(s) if($serversalt) { - my $hash1 = hash_string(${serversalt}.$ENV{'CGIMasterKey'}); + my $hash1 = hash_string(${serversalt}.$masterkey); my $CryptKey = hash_string(${'hash1'}.$ticket->{'Username'}->[0]); foreach my $password (@{$ticket->{Password}}) { @@ -3832,7 +3924,7 @@ sub DecryptTicketWithMasterKey # ($ticket, $serversalt) -> \@password_list }; return $ticket->{Password}; }; -sub EncryptTicketWithMasterKey # ($ticket, $serversalt) -> \@password_list +sub EncryptTicketWithMasterKey # ($ticket, $serversalt [, $masterkey]) -> \@password_list { DecryptTicketWithMasterKey(@_); }; -- 2.11.4.GIT