* Fixed a couple bugs to get System->change_shell_user_password() working.

* Made logging between journald and a traditional file configurable via 'sys::log_file'. Also made the file handle unbuffered when logging to a file.
* Fixed a bug with loading the anvil.conf config file in a few locations.
* Created System->stty_echo() to handle enabling/disabling shell echo, and added restoring the echo to Tools->catch_sig.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 7 years ago
parent b42d4a6fea
commit eafd4fd3f7
  1. 10
      Anvil/Tools.pm
  2. 39
      Anvil/Tools/Log.pm
  3. 2
      Anvil/Tools/Storage.pm
  4. 47
      Anvil/Tools/System.pm
  5. 6
      ocf/alteeve/server
  6. 2
      share/words.xml
  7. 38
      tools/anvil-change-password
  8. 2
      tools/anvil-configure-network
  9. 3
      tools/anvil-prep-database

@ -697,6 +697,8 @@ sub _set_defaults
user => "admin",
},
host_type => "",
log_file => "/var/log/anvil.log",
stty => "",
use_base2 => 1,
};
$anvil->data->{defaults} = {
@ -798,6 +800,7 @@ sub _set_paths
md5sum => "/usr/bin/md5sum",
'mkdir' => "/usr/bin/mkdir",
nmcli => "/bin/nmcli",
openssl => "/usr/bin/openssl",
passwd => "/usr/bin/passwd",
ping => "/usr/bin/ping",
pgrep => "/usr/bin/pgrep",
@ -919,6 +922,13 @@ sub catch_sig
if ($signal)
{
print "Process with PID: [$$] exiting on SIG".$signal.".\n";
if ($anvil->data->{sys}{stty})
{
# Restore the terminal.
print "Restoring the terminal\n";
$anvil->System->call({shell_call => $anvil->data->{path}{exe}{stty}." ".$anvil->data->{sys}{stty}});
}
}
$anvil->nice_exit({code => 255});
}

@ -301,19 +301,8 @@ sub entry
$string .= $message;
}
# Log with Log::Journald
if (0)
{
Log::Journald::send(
PRIORITY => $priority,
MESSAGE => $string,
CODE_FILE => $source,
CODE_LINE => $line,
SYSLOG_FACILITY => $secure ? "authpriv" : $facility,
SYSLOG_IDENTIFIER => $tag,
);
}
else
# If the user set a log file, log to that. Otherwise, log via Log::Journald.
if ($anvil->data->{sys}{log_file})
{
# TODO: Switch back to journald later, using a file for testing for now
if ($string !~ /\n$/)
@ -324,10 +313,18 @@ sub entry
# Open the file?
if (not $anvil->{HANDLE}{log_file})
{
my $shell_call = "/var/log/anvil.log";
# If the file doesn't start with a '/', we'll put it under /var/log.
my $log_file = $anvil->data->{sys}{log_file} =~ /^\// ? $anvil->data->{sys}{log_file} : "/var/log/".$anvil->data->{sys}{log_file};
my ($directory, $file) = ($log_file =~ /^(\/.*)\/(.*)$/);
# Make sure the log directory exists.
$anvil->Storage->make_directory({directory => $directory, group => 755});
# Now open the log
my $shell_call = $log_file;
# NOTE: Don't call '$anvil->Log->entry()' here, it will cause a loop!
open (my $file_handle, ">>", $shell_call) or die "Failed to open: [$shell_call] for writing. The error was: $!\n";
$file_handle->autoflush(1);
$anvil->{HANDLE}{log_file} = $file_handle;
}
@ -340,6 +337,17 @@ sub entry
# The handle has to be wrapped in a block to make 'print' happy as it doesn't like non-scalars for file handles
print { $anvil->{HANDLE}{log_file} } $string;
}
else
{
Log::Journald::send(
PRIORITY => $priority,
MESSAGE => $string,
CODE_FILE => $source,
CODE_LINE => $line,
SYSLOG_FACILITY => $secure ? "authpriv" : $facility,
SYSLOG_IDENTIFIER => $tag,
);
}
return(0);
}
@ -560,6 +568,7 @@ sub variables
{
die $THIS_FILE." ".__LINE__."; Log->variables() called without Log->level: [".$anvil->Log->level."] defined from: [$source : $line]\n";
}
#print "level: [$level], logging: [".$anvil->Log->level."], secure: [$secure], logging secure: [".$anvil->Log->secure."]\n";
if ($level > $anvil->Log->level)
{
return(1);

@ -745,7 +745,7 @@ sub read_config
if (not $file)
{
# No file to read
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "log_0032"});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "log_0164"});
$return_code = 1;
}

@ -29,6 +29,7 @@ my $THIS_FILE = "System.pm";
# reload_daemon
# start_daemon
# stop_daemon
# stty_echo
# _load_firewalld_zones
# _load_specific_firewalld_zone
# _match_port_to_service
@ -182,7 +183,6 @@ sub call
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { output => $output }});
return($output);
}
@ -264,8 +264,8 @@ sub change_shell_user_password
}
# Generate a salt and then use it to create a hash.
my $salt = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{openssl}." rand 1000 | ".$anvil->data->{path}{exe}{strings}." | ".$anvil->data->{path}{exe}{'grep'}." -io [0-9A-Za-z\.\/] | ".$anvil->data->{path}{exe}{head}." -n 16 | ".$anvil->data->{path}{exe}{'tr'}." -d '\n'" });
my $new_hash = $user.":".crypt($new_password,"\$6\$".$salt."\$");
my $salt = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{openssl}." rand 1000 | ".$anvil->data->{path}{exe}{strings}." | ".$anvil->data->{path}{exe}{'grep'}." -io [0-9A-Za-z\.\/] | ".$anvil->data->{path}{exe}{head}." -n 16 | ".$anvil->data->{path}{exe}{'tr'}." -d '\n'" });
my $new_hash = crypt($new_password,"\$6\$".$salt."\$");
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 0, list => {
salt => $salt,
new_hash => $new_hash,
@ -273,11 +273,12 @@ sub change_shell_user_password
# Update the password using 'usermod'. NOTE: The single-quotes are crtical!
my $output = "";
my $shell_call = $anvil->data->{path}{exe}{usermod}." --password '".$new_hash."'; ".$anvil->data->{path}{exe}{'echo'}." return_code:\$?";
my $shell_call = $anvil->data->{path}{exe}{usermod}." --password '".$new_hash."' ".$user."; ".$anvil->data->{path}{exe}{'echo'}." return_code:\$?";
if ($target)
{
# Remote call.
$output = $anvil->Remote->call({
debug => $debug,
shell_call => $shell_call,
target => $target,
port => $port,
@ -288,7 +289,7 @@ sub change_shell_user_password
else
{
# Local call
$output = $anvil->System->call({shell_call => $shell_call});
$output = $anvil->System->call({debug => $debug, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output }});
}
foreach my $line (split/\n/, $output)
@ -1481,6 +1482,42 @@ sub stop_daemon
return($return);
}
=head2 stty_echo
This turns echo off (for password prompts, for example) and back on again. It does so in a way that a SIGINT/SIGKILL can restore the echo before the program dies.
B<< Note >>: Calling C<< on >> before C<< off >> will result in no change. The C<< off >> stores the current TTY in C<< sys::stty >> and uses the value in there to reset the terminal. If you want to change the terminal, you can set that variable manually then call C<< on >>, though this is not recommended.
Parameters;
=head3 set (required, default 'on')
This is set to C<< on >> or C<< off >>, which enables or disables echo'ing respectively.
=cut
sub stty_echo
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
my $set = defined $parameter->{set} ? $parameter->{set} : "";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0018", variables => { set => $set }});
if ($set eq "off")
{
$anvil->data->{sys}{stty} = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{stty}." --save"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => { 'sys::stty' => $anvil->data->{sys}{stty} }});
$anvil->System->call({shell_call => $anvil->data->{path}{exe}{stty}." -echo"});
}
elsif (($set eq "on") && ($anvil->data->{sys}{stty}))
{
$anvil->System->call({shell_call => $anvil->data->{path}{exe}{stty}." ".$anvil->data->{sys}{stty}});
}
return(0);
}
# =head3
#

@ -97,7 +97,7 @@ my $conf = {
},
# If a program isn't at the defined path, $ENV{PATH} will be searched.
path => {
config => {
configs => {
definition => "/mnt/anvil/definitions/#!NAME!#.xml",
},
exe => {
@ -351,7 +351,7 @@ sub start_server
# If we're still alive, we're ready to boot.
to_log($conf, {message => "Sanity checks passed, ready to start: [$server].", 'line' => __LINE__, level => 2});
my $definition_file = $conf->{path}{config}{definition};
my $definition_file = $conf->{path}{configs}{definition};
$definition_file =~ s/#!NAME!#/$server/;
to_log($conf, {message => "definition_file: [$definition_file].", 'line' => __LINE__, level => 2});
@ -1545,7 +1545,7 @@ sub read_server_definition
my ($conf) = @_;
my $server = $conf->{environment}{OCF_RESKEY_name};
my $definition_file = $conf->{path}{config}{definition};
my $definition_file = $conf->{path}{configs}{definition};
$definition_file =~ s/#!NAME!#/$server/;
my $server_xml = "";
to_log($conf, {message => "server: [$server], definition_file: [$definition_file]", 'line' => __LINE__, level => 3});

@ -44,6 +44,7 @@ Author: Madison Kelly <mkelly@alteeve.ca>
<key name="message_0020">About to update the local passwords (shell users, database and web interface).</key>
<key name="message_0021">Proceed? [y/N]</key>
<key name="message_0022">Aborting.</key>
<key name="message_0023">Auto-approved by command line switch, proceeding.</key>
<!-- Log entries -->
<key name="log_0001">Starting: [#!variable!program!#].</key>
@ -242,6 +243,7 @@ The database connection error was:
<key name="log_0161"><![CDATA[[ Error ] - The method Storage->read_file() was asked to read the remote file: [#!variable!file!#] but it appears to be missing the file name. Aborting.]]></key>
<key name="log_0162"><![CDATA[[ Error ] - The method Storage->read_file() tried to rsync the remote file: [#!variable!remote_file!#] to the local temporary file: [#!variable!local_file!#], but it did not arrive. There might be more information above.]]></key>
<key name="log_0163">The file: [#!variable!file!#] does not exist.</key>
<key name="log_0164"><![CDATA[[ Warning ] - Storage->read_config()' was called without a file name to read.]]></key>
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">Test</key>

@ -31,13 +31,13 @@ $( = $);
my $anvil = Anvil::Tools->new();
$anvil->Log->level({set => 2});
$anvil->Log->secure({set => 0});
$anvil->Log->secure({set => 1});
# Read switches
$anvil->Get->switches;
# Paths
$anvil->Storage->read_config({file => $anvil->data->{path}{config}{'anvil.conf'}});
$anvil->Storage->read_config({file => $anvil->data->{path}{configs}{'anvil.conf'}});
# Make sure we're running as 'root'
# $< == real UID, $> == effective UID
@ -62,17 +62,20 @@ if (not $connections)
# 1. If we've been told of a password file, read it
# 2. If the user passed the password with --new-password <secret>, use that.
# 3. Ask the user for the new password.
if ($anvil->data->{switches}{password_file})
if ($anvil->data->{switches}{'password-file'})
{
# Read the password in from the file.
if (-e $anvil->data->{switches}{password_file})
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => { "switches::password-file" => $anvil->data->{switches}{'password-file'} }});
if (-e $anvil->data->{switches}{'password-file'})
{
$anvil->data->{switches}{'new-password'} = $anvil->Storage->read_file({file => $anvil->data->{switches}{password_file}});
# Read it in and remove the new-line(s), if it(they) exist.
$anvil->data->{switches}{'new-password'} = $anvil->Storage->read_file({file => $anvil->data->{switches}{'password-file'}});
$anvil->data->{switches}{'new-password'} =~ s/\n//gs;
}
else
{
# The file doesn't exist.
print $anvil->Words->string({key => "error_0008", variables => { file => $anvil->data->{switches}{password_file} }});
print $anvil->Words->string({key => "error_0008", variables => { file => $anvil->data->{switches}{'password-file'} }});
$anvil->nice_exit({exit_code => 4});
}
}
@ -80,15 +83,13 @@ elsif (not $anvil->data->{switches}{'new-password'})
{
print $anvil->Words->string({key => "message_0018"})."\n";
# Turn off echo
my $old_stty = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{stty}." --save"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => { old_stty => $old_stty }});
$anvil->System->call({shell_call => $anvil->data->{path}{exe}{stty}." -echo"});
$anvil->System->stty_echo({set => "off"});
my $password1 = <STDIN>;
chomp($password1);
$password1 =~ s/^\s+//;
$password1 =~ s/\s+$//;
# Turn echo on
$anvil->System->call({shell_call => $anvil->data->{path}{exe}{stty}." ".$old_stty});
$anvil->System->stty_echo({set => "on"});
if (not $password1)
{
@ -98,18 +99,18 @@ elsif (not $anvil->data->{switches}{'new-password'})
print $anvil->Words->string({key => "message_0019"})."\n";
# Turn off echo
$anvil->System->call({shell_call => $anvil->data->{path}{exe}{stty}." -echo"});
$anvil->System->stty_echo({set => "off"});
my $password2 = <STDIN>;
chomp($password2);
$password2 =~ s/^\s+//;
$password2 =~ s/\s+$//;
# Turn echo on
$anvil->System->call({shell_call => $anvil->data->{path}{exe}{stty}." ".$old_stty});
$anvil->System->stty_echo({set => "on"});
if ($password1 eq $password2)
{
$anvil->data->{switches}{'new-password'} = $password1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { "switches::new_password" => $anvil->data->{switches}{'new-password'} }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { "switches::new-password" => $anvil->data->{switches}{'new-password'} }});
}
else
{
@ -130,6 +131,14 @@ else
{
### TODO: Support '--peers' to also update the peer dashboards.
# Updating just ourself
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { "switches::new-password" => $anvil->data->{switches}{'new-password'} }});
if (($anvil->data->{switches}{y}) or ($anvil->data->{switches}{yes}))
{
print $anvil->Words->string({key => "message_0023"})."\n";
update_local_passwords($anvil);
}
else
{
print $anvil->Words->string({key => "message_0020"})."\n";
print $anvil->Words->string({key => "message_0021"})." ";
my $answer = <STDIN>;
@ -143,6 +152,7 @@ else
# Abort.
print $anvil->Words->string({key => "message_0022"})."\n";
}
}
}
@ -161,7 +171,7 @@ sub update_local_passwords
foreach my $user ("admin", "root")
{
print "Updating: [$user] with password: [".$anvil->data->{switches}{'new-password'}."]\n";
$anvil->System->change_shell_user_password({user => $user, new_password => $anvil->data->{switches}{'new-password'}});
$anvil->System->change_shell_user_password({debug => 2, user => $user, new_password => $anvil->data->{switches}{'new-password'}});
}
# Update the database password.

@ -33,7 +33,7 @@ $anvil->Log->secure({set => 0});
$anvil->Get->switches;
# Paths
$anvil->Storage->read_config({file => $anvil->data->{path}{config}{'anvil.conf'}});
$anvil->Storage->read_config({file => $anvil->data->{path}{configs}{'anvil.conf'}});
# Make sure we're running as 'root'
# $< == real UID, $> == effective UID

@ -34,8 +34,7 @@ $anvil->Log->secure({set => 1});
$anvil->Get->switches;
# Paths
$anvil->data->{path}{config}{'anvil.conf'} = "/etc/anvil/anvil.conf";
$anvil->Storage->read_config({file => $anvil->data->{path}{config}{'anvil.conf'}});
$anvil->Storage->read_config({file => $anvil->data->{path}{configs}{'anvil.conf'}});
my $local_id = $anvil->Database->get_local_id;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { local_id => $local_id }});

Loading…
Cancel
Save