From 6f74ca376b585a5db7a2a516449e978f25e2cab3 Mon Sep 17 00:00:00 2001 From: Digimer Date: Wed, 11 Sep 2019 12:58:57 -0400 Subject: [PATCH] * Created anvil-daemon->check_setuid_wrappers() function that will dynamically create setuid c-wrappers on daemon startup, when needed. * Updated variable names to clarify their purpose in striker. Signed-off-by: Digimer --- Anvil/Tools.pm | 1 + Anvil/Tools/Storage.pm | 6 +-- cgi-bin/striker | 29 ++++++++------ share/words.xml | 3 ++ tools/anvil-daemon | 88 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 15 deletions(-) diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index ef64631c..71d5a770 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -1031,6 +1031,7 @@ sub _set_paths expect => "/usr/bin/expect", 'firewall-cmd' => "/usr/bin/firewall-cmd", free => "/usr/bin/free", + gcc => "/usr/bin/gcc", getent => "/usr/bin/getent", gethostip => "/usr/bin/gethostip", 'grep' => "/usr/bin/grep", diff --git a/Anvil/Tools/Storage.pm b/Anvil/Tools/Storage.pm index b8fa418a..e6656990 100644 --- a/Anvil/Tools/Storage.pm +++ b/Anvil/Tools/Storage.pm @@ -420,9 +420,9 @@ sub change_owner my $group = defined $parameter->{group} ? $parameter->{group} : getgrgid($(); my $user = defined $parameter->{user} ? $parameter->{user} : getpwuid($<); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - path => $path, - group => $group, - user => $user, + path => $path, + group => $group, + user => $user, }}); # Make sure the user and group and just one digit or word. diff --git a/cgi-bin/striker b/cgi-bin/striker index 73edf1a9..c784850a 100755 --- a/cgi-bin/striker +++ b/cgi-bin/striker @@ -988,11 +988,11 @@ sub add_sync_peer ping => $ping, }}); - my $pgsql_port = 5432; - my $ssh_port = 22; - my $peer_uuid = ""; - my $peer_host = ""; - my $use_ip = ""; # This will contain the local IP to use for the peer to setup comms with us + my $pgsql_port = 5432; + my $ssh_port = 22; + my $peer_host_uuid = ""; + my $peer_host_name = ""; + my $use_ip = ""; # This will contain the local IP to use for the peer to setup comms with us if ($host =~ /,ssh=(\d+)$/) { $ssh_port = $1; @@ -1083,23 +1083,28 @@ sub add_sync_peer $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); if ($line =~ /host_name=(.*)$/) { - $peer_host = $1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host => $peer_host }}); + # We collect this, but apparently not for any real reason... + $peer_host_name = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host_name => $peer_host_name }}); } if ($line =~ /host_uuid=(.*)$/) { - $peer_uuid = $1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_uuid => $peer_uuid }}); + $peer_host_uuid = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host_uuid => $peer_host_uuid }}); } } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + peer_host_name => $peer_host_name, + peer_host_uuid => $peer_host_uuid, + }}); # Make sure the database entry is gone (striker-get-peer-data should have removed it, but lets be safe). my $query = "DELETE FROM states WHERE state_name = ".$anvil->Database->quote("peer::".$host."::password").";"; $anvil->Database->write({uuid => $anvil->data->{sys}{host_uuid}, debug => 2, query => $query, source => $THIS_FILE, line => __LINE__}); - if (not $anvil->Validate->is_uuid({uuid => $peer_uuid})) + if (not $anvil->Validate->is_uuid({uuid => $peer_host_uuid})) { - $anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "striker_warning_0005", variables => { uuid => $peer_uuid }}) }}); + $anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "striker_warning_0005", variables => { uuid => $peer_host_uuid }}) }}); } # Lastly, if bi-directional is set, make sure we have a way to talk to it. @@ -1169,7 +1174,7 @@ sub add_sync_peer if ($anvil->data->{cgi}{confirm}{value}) { # OK, save the job! - my $job_command = $anvil->data->{path}{exe}{'striker-manage-peers'}." --add --host-uuid ".$peer_uuid." --host ".$host." --port ".$pgsql_port." --ping ".$ping; + my $job_command = $anvil->data->{path}{exe}{'striker-manage-peers'}." --add --host-uuid ".$peer_host_uuid." --host ".$host." --port ".$pgsql_port." --ping ".$ping; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_command => $job_command, password => $anvil->Log->is_secure($password), diff --git a/share/words.xml b/share/words.xml index 53e995b0..cad26a2a 100644 --- a/share/words.xml +++ b/share/words.xml @@ -758,6 +758,7 @@ Failed to promote the DRBD resource: [#!variable!resource!#] primary. Expected a The 'smaps' proc file for the process ID: [#!variable!pid!#] was not found. Did the program just close? - The DRBD resource: [#!variable!resource!#] is in the role: [#!variable!role!#] already, no need to bring it up. Program: [#!variable!program!#] running as the real user: [#!variable!real_user!# (#!variable!real_uid!#)] and effective user: [#!variable!effective_user!# (#!variable!effective_uid!#)]. + The setuid c-wrapper: [#!variable!wrapper!#] already exists, no need to create it. Test @@ -1051,6 +1052,8 @@ Failed to generate an RSA public key for the user: [#!variable!user!#]. The outp + Something went wrong trying to write: [#!variable!file!#], unable to proceed. + Something went wrong trying to compile the C-program: [#!variable!file!#], unable to proceed. Yes diff --git a/tools/anvil-daemon b/tools/anvil-daemon index 36d22b5b..fdd1b745 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -810,6 +810,9 @@ sub run_once # Check the ssh stuff. check_ssh_keys($anvil); + # Check setuid wrappers + check_setuid_wrappers($anvil); + if ($anvil->data->{switches}{'startup-only'}) { $anvil->nice_exit({code => 0}); @@ -818,6 +821,91 @@ sub run_once return(0); } +# This creates, as needed, the setuid wrappers used by apache to make certain system calls. +sub check_setuid_wrappers +{ + my ($anvil) = @_; + + # Does the call_striker-get-peer-data wrapper exist yet? + if (-e $anvil->data->{path}{exe}{'call_striker-get-peer-data'}) + { + # Exists, skipping. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0436", variables => { wrapper => $anvil->data->{path}{exe}{'call_striker-get-peer-data'} }}); + } + else + { + # What is the admin user and group ID? + my $admin_uid = getpwnam('admin'); + my $admin_gid = getgrnam('admin'); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + admin_uid => $admin_uid, + admin_gid => $admin_gid, + }}); + next if not $admin_uid; + next if not $admin_gid; + + # Write the body out + my $call_striker_get_peer_data_body = "#define REAL_PATH \"".$anvil->data->{path}{exe}{'striker-get-peer-data'}."\"\n"; + $call_striker_get_peer_data_body .= "main(ac, av)\n"; + $call_striker_get_peer_data_body .= "char **av;\n"; + $call_striker_get_peer_data_body .= "{\n"; + $call_striker_get_peer_data_body .= " setuid(".$admin_uid.");\n"; + $call_striker_get_peer_data_body .= " setgid(".$admin_gid.");\n"; + $call_striker_get_peer_data_body .= " execv(REAL_PATH, av);\n"; + $call_striker_get_peer_data_body .= "}\n"; + my $error = $anvil->Storage->write_file({ + debug => 2, + file => $anvil->data->{path}{exe}{'call_striker-get-peer-data'}.".c", + body => $call_striker_get_peer_data_body, + mode => '644', + overwrite => 1, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { error => $error }}); + + # If it wrote out, compile it. + if (not -e $anvil->data->{path}{exe}{'call_striker-get-peer-data'}.".c") + { + # Failed to write. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "error_0071", variables => { file => $anvil->data->{path}{exe}{'call_striker-get-peer-data'}.".c" }}); + } + else + { + # Compile it + my ($output, $return_code) = $anvil->System->call({ + debug => 2, + shell_call => $anvil->data->{path}{exe}{gcc}." -o ".$anvil->data->{path}{exe}{'call_striker-get-peer-data'}." ".$anvil->data->{path}{exe}{'call_striker-get-peer-data'}.".c", + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + output => $output, + return_code => $return_code, + }}); + + # If it compiled, setuid it. + if (not -e $anvil->data->{path}{exe}{'call_striker-get-peer-data'}) + { + # Something went wrong compiling it. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "error_0072", variables => { file => $anvil->data->{path}{exe}{'call_striker-get-peer-data'}.".c" }}); + } + else + { + $anvil->Storage->change_owner({ + debug => 2, + path => $anvil->data->{path}{exe}{'call_striker-get-peer-data'}, + user => 'root', + group => 'root', + }); + $anvil->Storage->change_mode({ + debug => 2, + path => $anvil->data->{path}{exe}{'call_striker-get-peer-data'}, + mode => '4755', + }); + } + } + } + + return(0); +} + # Configure/update the firewall. sub check_firewall {