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:
+
+- salt=[file or string]
Server salt value to use io the value
+ stored in the ticket file. Will replace the stored value if a new
+ password is given. If you change the server salt, you have to
+ reset all the passwords. There is absolutely no procedure known
+ to recover plaintext passwords, except asking the account holders.
+ You are strongly adviced to make a backup before you apply such a change
+- masterkey=[file or string]
CGIMasterKey used to read and decrypt
+ the ticket
+- newmasterkey=[file or string]
CGIMasterKey used to encrypt, sign,
+ and write the ticket. Defaults to the masterkey. If you change
+ the masterkey, you will have to reset all the accounts. You are strongly
+ adviced to make a backup before you apply such a change
+- password=[file or string]
New plaintext password
+
+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