* Added support to specify @group values for the --targets parameter and in the targets file(s)

* Added support for nested aliases: up to 5 levels deep instead of just
one level
* Added --resolve-alias/--alias command-line parameter to manually check
the resolution any alias
* Fixed propagation of --debug flag (to clients & slaves)
* Fixed propagation of --create-dir flag (to clients & slaves)
* Fixed problem in --fix-local routine (by adding optional --fix-user
command-line parameter and code)
* Fixed check when adding key to ssh-agent
* Added checking on alias resolution in --check-syntax routine
* Better trap setting
* Added typeset-ing to vars
* Switched version numbering (now date based)
* Code cleanup (now error & warning free in shellcheck/perlcritic
linters)
This commit is contained in:
patvdv 2018-11-03 16:35:59 +01:00
parent 4e464ffeb0
commit af9ed19d6b
3 changed files with 684 additions and 295 deletions

View File

@ -13,7 +13,7 @@
# (leave blank for current user) # (leave blank for current user)
SUDO_TRANSFER_USER="" SUDO_TRANSFER_USER=""
# name of the OS group that should own the SUDO controls files # name of the UNIX group that should own the SUDO controls files (must exist already)
SUDO_OWNER_GROUP="sudoadmin" SUDO_OWNER_GROUP="sudoadmin"
# whether a 'chmod' needs to be executed after each sftp transfer [0=No; 1=Yes] # whether a 'chmod' needs to be executed after each sftp transfer [0=No; 1=Yes]
@ -45,7 +45,7 @@ VISUDO_BIN="/usr/sbin/visudo"
# path to the ssh-keyscan too # path to the ssh-keyscan too
SSH_KEYSCAN_BIN="/usr/bin/ssh-keyscan" SSH_KEYSCAN_BIN="/usr/bin/ssh-keyscan"
# extra arguments/options for the ssh-keyscan command # extra arguments/options for the ssh-keyscan command
# by default -f <file> is used by manage_sudo.sh to supply hostnames, do not add here # by default -f <file> is used by manage_sudo.sh to supply hostnames, do not add here
SSH_KEYSCAN_ARGS="-t rsa" SSH_KEYSCAN_ARGS="-t rsa"

File diff suppressed because it is too large Load Diff

View File

@ -43,21 +43,23 @@ use File::Temp qw(tempfile);
#****************************************************************************** #******************************************************************************
# ------------------------- CONFIGURATION starts here ------------------------- # ------------------------- CONFIGURATION starts here -------------------------
# define the V.R.F (version/release/fix) # define the version (YYYY-MM-DD)
my $MY_VRF = "1.1.4"; my $script_version = "2018-11-03";
# name of global configuration file (no path, must be located in the script directory) # name of global configuration file (no path, must be located in the script directory)
my $global_config_file = "update_sudo.conf"; my $global_config_file = "update_sudo.conf";
# name of localized configuration file (no path, must be located in the script directory) # name of localized configuration file (no path, must be located in the script directory)
my $local_config_file = "update_sudo.conf.local"; my $local_config_file = "update_sudo.conf.local";
# maxiumum level of recursion for alias resolution
my $max_recursion = 5;
# selinux context label of sudoers fragment files # selinux context label of sudoers fragment files
my $selinux_context = "etc_t"; my $selinux_context = "etc_t";
# ------------------------- CONFIGURATION ends here --------------------------- # ------------------------- CONFIGURATION ends here ---------------------------
# initialize variables # initialize variables
my ($debug, $verbose, $preview, $global, $use_fqdn) = (0,0,0,0,0); my ($debug, $verbose, $preview, $global, $use_fqdn) = (0,0,0,0,0);
my (@config_files, $fragments_dir, $visudo_bin, $immutable_self_file, $immutable_self_cmd); my (@config_files, $fragments_dir, $visudo_bin, $immutable_self_file, $immutable_self_cmd);
my (%options, @uname, %aliases, %frags, @grants); my (%options, @uname, %aliases, %frags, @grants);
my ($os, $host, $hostname, $run_dir); my ($os, $host, $hostname, $run_dir);
my ($selinux_status, $has_selinux) = ("",0); my ($selinux_status, $has_selinux, $recursion_count) = ("",0,1);
$|++; $|++;
@ -67,7 +69,7 @@ $|++;
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
sub do_log { sub do_log {
my $message = shift; my $message = shift;
if ($message =~ /^ERROR:/ || $message =~ /^WARN:/) { if ($message =~ /^ERROR:/ || $message =~ /^WARN:/) {
@ -87,7 +89,7 @@ sub parse_config_file {
my $config_file = shift; my $config_file = shift;
unless (open (CONF_FD, "<", $config_file)) { unless (open (CONF_FD, "<", $config_file)) {
do_log ("ERROR: failed to open the configuration file ${config_file} [$! $hostname]") do_log ("ERROR: failed to open the configuration file ${config_file} [$! $hostname]")
and exit (1); and exit (1);
} }
while (<CONF_FD>) { while (<CONF_FD>) {
@ -118,7 +120,7 @@ sub parse_config_file {
} }
} }
} }
# parameter checks # parameter checks
if (not defined ($immutable_self_file) or $immutable_self_file eq "") { if (not defined ($immutable_self_file) or $immutable_self_file eq "") {
do_log ("ERROR: 'immutable_self_file' parameter not defined [$hostname]") do_log ("ERROR: 'immutable_self_file' parameter not defined [$hostname]")
@ -138,7 +140,7 @@ sub resolve_aliases
foreach $entry (@tmp_array) { foreach $entry (@tmp_array) {
if ($entry =~ /^\@/) { if ($entry =~ /^\@/) {
($aliases{$entry}) ($aliases{$entry})
? push (@new_array, @{$aliases{$entry}}) ? push (@new_array, @{$aliases{$entry}})
: do_log ("WARN: unable to resolve alias $entry [$hostname]"); : do_log ("WARN: unable to resolve alias $entry [$hostname]");
} else { } else {
($entry) ($entry)
@ -153,14 +155,14 @@ sub resolve_aliases
sub set_file { sub set_file {
my ($file, $perm, $uid, $gid) = @_; my ($file, $perm, $uid, $gid) = @_;
chmod ($perm, "$file") chmod ($perm, "$file")
or do_log ("ERROR: cannot set permissions on $file [$! $hostname]") or do_log ("ERROR: cannot set permissions on $file [$! $hostname]")
and exit (1); and exit (1);
chown ($uid, $gid, "$file") chown ($uid, $gid, "$file")
or do_log ("ERROR: cannot set ownerships on $file [$! $hostname]") or do_log ("ERROR: cannot set ownerships on $file [$! $hostname]")
and exit (1); and exit (1);
return (1); return (1);
} }
@ -185,12 +187,12 @@ if ( @ARGV > 0 ) {
version|V version|V
)) || pod2usage(-verbose => 0); )) || pod2usage(-verbose => 0);
} }
pod2usage(-verbose => 0) unless (%options); pod2usage(-verbose => 0) unless (%options);
# check version parameter # check version parameter
if ($options{'version'}) { if ($options{'version'}) {
$verbose = 1; $verbose = 1;
do_log ("INFO: $0: version $MY_VRF"); do_log ("INFO: $0: version $script_version");
exit (0); exit (0);
} }
# check help parameter # check help parameter
@ -207,7 +209,7 @@ if ($options{'preview'}) {
$preview = 1; $preview = 1;
$verbose = 1; $verbose = 1;
if ($global) { if ($global) {
do_log ("INFO: running in GLOBAL PREVIEW mode"); do_log ("INFO: running in GLOBAL PREVIEW mode");
} else { } else {
do_log ("INFO: running in PREVIEW mode"); do_log ("INFO: running in PREVIEW mode");
} }
@ -235,7 +237,7 @@ do_log ("INFO: parsing configuration file(s) ...");
push (@config_files, "$run_dir/$global_config_file") if (-f "$run_dir/$global_config_file"); push (@config_files, "$run_dir/$global_config_file") if (-f "$run_dir/$global_config_file");
push (@config_files, "$run_dir/$local_config_file") if (-f "$run_dir/$local_config_file"); push (@config_files, "$run_dir/$local_config_file") if (-f "$run_dir/$local_config_file");
unless (@config_files) { unless (@config_files) {
do_log ("ERROR: unable to find any configuration file, bailing out [$hostname]") do_log ("ERROR: unable to find any configuration file, bailing out [$hostname]")
and exit (1); and exit (1);
} }
@ -250,7 +252,7 @@ unless ($preview and $global) {
if (-d $fragments_dir) { if (-d $fragments_dir) {
do_log ("INFO: host is under SUDO control via $fragments_dir"); do_log ("INFO: host is under SUDO control via $fragments_dir");
} else { } else {
do_log ("ERROR: host is not under SUDO control [$hostname]") do_log ("ERROR: host is not under SUDO control [$hostname]")
and exit (1); and exit (1);
} }
} }
@ -258,7 +260,7 @@ unless ($preview and $global) {
# is syntax checking possible? (not for global preview) # is syntax checking possible? (not for global preview)
unless ($preview and $global) { unless ($preview and $global) {
unless (-x $visudo_bin) { unless (-x $visudo_bin) {
do_log ("ERROR: 'visudo' tool could not be found, will not continue [$hostname]") do_log ("ERROR: 'visudo' tool could not be found, will not continue [$hostname]")
and exit (1); and exit (1);
} }
} }
@ -269,7 +271,7 @@ $os = $uname[0];
# who am I? # who am I?
unless ($preview and $global) { unless ($preview and $global) {
if ($< != 0) { if ($< != 0) {
do_log ("ERROR: script must be invoked as user 'root' [$hostname]") do_log ("ERROR: script must be invoked as user 'root' [$hostname]")
and exit (1); and exit (1);
} }
} }
@ -294,7 +296,7 @@ open (ALIASES, "<", "${run_dir}/alias")
while (<ALIASES>) { while (<ALIASES>) {
my ($key, $value, @values); my ($key, $value, @values);
chomp (); chomp ();
next if (/^$/ || /\#/); next if (/^$/ || /\#/);
s/\s+//g; s/\s+//g;
@ -307,13 +309,44 @@ close (ALIASES);
do_log ("DEBUG: dumping unexpanded aliases:"); do_log ("DEBUG: dumping unexpanded aliases:");
print Dumper (\%aliases) if $debug; print Dumper (\%aliases) if $debug;
# we can nest aliases one level deep, so do a one-level recursive sort of lookup # resolve aliases recursively to a maxium of $max_recursion
# of the remaining '@' aliases. Input should be passed as comma-separated while ($recursion_count <= $max_recursion) {
# string to resolve_aliases so don't forget to smash everything back together # crawl over all items in the hash %aliases
# first. foreach my $key (keys (%aliases)) {
foreach my $key (keys (%aliases)) { # crawl over all items in the array @{aliases{$key}}
my @new_array; my @filtered_array; # these are the working stashes
$aliases{$key} = [resolve_aliases (join (",", @{$aliases{$key}}))]; do_log ("DEBUG: expanded alias $key before recursion $recursion_count [$hostname]");
print Dumper (\@{$aliases{$key}}) if $debug;
foreach my $item (@{$aliases{$key}}) {
# is it a group?
if ($item =~ /^\@/) {
# expand the group if it exists
if ($aliases{$item}) {
# add current and new items to the working stash
if (@new_array) {
push (@new_array, @{$aliases{$item}});
} else {
@new_array = (@{$aliases{$key}}, @{$aliases{$item}});
}
# remove the original group item from the working stash
@filtered_array = grep { $_ ne $item } @new_array;
@new_array = @filtered_array;
} else {
do_log ("WARN: unable to resolve alias $item [$hostname]");
}
# no group, just add the item as-is to working stash
} else {
push (@new_array, $item);
}
}
my %seen;
@filtered_array = grep { not $seen{$_}++ } @new_array;
# re-assign working stash back to our original hash key
@{$aliases{$key}} = @filtered_array;
do_log ("DEBUG: expanded alias $key after recursion $recursion_count [$hostname]");
print Dumper (\@{$aliases{$key}}) if $debug;
}
$recursion_count++;
} }
do_log ("INFO: ".scalar (keys (%aliases))." aliases found on $hostname"); do_log ("INFO: ".scalar (keys (%aliases))." aliases found on $hostname");
@ -321,8 +354,8 @@ do_log ("DEBUG: dumping expanded aliases:");
print Dumper (\%aliases) if $debug; print Dumper (\%aliases) if $debug;
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# read SUDO fragments stored in a single 'fragments' file or in # read SUDO fragments stored in a single 'fragments' file or in
# individual fragment files from a 'fragments.d' directory # individual fragment files from a 'fragments.d' directory
# result: %frags # result: %frags
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -337,43 +370,43 @@ if (-d "${run_dir}/fragments.d" && -f "${run_dir}/fragments") {
if (-d "${run_dir}/fragments.d") { if (-d "${run_dir}/fragments.d") {
do_log ("INFO: local 'fragments' are stored in a DIRECTORY on $hostname"); do_log ("INFO: local 'fragments' are stored in a DIRECTORY on $hostname");
opendir (FRAGS_DIR, "${run_dir}/fragments.d") opendir (FRAGS_DIR, "${run_dir}/fragments.d")
or do_log ("ERROR: cannot open 'fragments.d' directory [$! $hostname]") or do_log ("ERROR: cannot open 'fragments.d' directory [$! $hostname]")
and exit (1); and exit (1);
while (my $frag_file = readdir (FRAGS_DIR)) { while (my $frag_file = readdir (FRAGS_DIR)) {
next if ($frag_file =~ /^\./); next if ($frag_file =~ /^\./);
push (@frag_files, "${run_dir}/fragments.d/$frag_file"); push (@frag_files, "${run_dir}/fragments.d/$frag_file");
} }
closedir (FRAGS_DIR); closedir (FRAGS_DIR);
} elsif (-f "${run_dir}/fragments") { } elsif (-f "${run_dir}/fragments") {
do_log ("INFO: local 'fragments' are stored in a FILE on $hostname"); do_log ("INFO: local 'fragments' are stored in a FILE on $hostname");
push (@frag_files, "${run_dir}/fragments"); push (@frag_files, "${run_dir}/fragments");
} else { } else {
do_log ("ERROR: cannot find any SUDO fragments in the repository! [$hostname]") do_log ("ERROR: cannot find any SUDO fragments in the repository! [$hostname]")
and exit (1); and exit (1);
} }
# process 'fragments' files # process 'fragments' files
foreach my $frag_file (@frag_files) { foreach my $frag_file (@frag_files) {
open (FRAGS, "<", $frag_file) open (FRAGS, "<", $frag_file)
or do_log ("ERROR: cannot read 'fragments' file [$! $hostname]") or do_log ("ERROR: cannot read 'fragments' file [$! $hostname]")
and exit (1); and exit (1);
do_log ("INFO: reading SUDO fragments from file: $frag_file"); do_log ("INFO: reading SUDO fragments from file: $frag_file");
my @frag_file = <FRAGS>; my @frag_file = <FRAGS>;
# check for fragments header(s): if there is no fragment header, then we # check for fragments header(s): if there is no fragment header, then we
# consider this a single fragment file, otherwise we consider it a # consider this a single fragment file, otherwise we consider it a
# collection of fragments that needs to be broken down in individual fragments # collection of fragments that needs to be broken down in individual fragments
if (grep { /^%%%/s } @frag_file) { if (grep { /^%%%/s } @frag_file) {
do_log ("INFO: fragment file $frag_file contains multiple fragments, parsing ..."); do_log ("INFO: fragment file $frag_file contains multiple fragments, parsing ...");
my ($frag_file, $frag_def); my ($frag_file, $frag_def);
my $count = 1; my $count = 1;
foreach (@frag_file) { foreach (@frag_file) {
# first header found # first header found
if (/^%%%/ && (not defined ($frag_def) or $frag_def eq "")) { if (/^%%%/ && (not defined ($frag_def) or $frag_def eq "")) {
@ -397,7 +430,7 @@ foreach my $frag_file (@frag_files) {
chomp ($frag_file); chomp ($frag_file);
unless (defined ($frag_file) && $frag_file ne "") { unless (defined ($frag_file) && $frag_file ne "") {
do_log ("WARN: no fragment file name found in header at line $count [$hostname]") do_log ("WARN: no fragment file name found in header at line $count [$hostname]")
} }
} else { } else {
# process fragment definition # process fragment definition
$frag_def .= $_; $frag_def .= $_;
@ -413,7 +446,7 @@ foreach my $frag_file (@frag_files) {
$frag_file = fileparse ($frag_file, qr/\.[^.]*/); $frag_file = fileparse ($frag_file, qr/\.[^.]*/);
do_log ("INFO: fragment file $frag_file contains only 1 fragment on $hostname"); do_log ("INFO: fragment file $frag_file contains only 1 fragment on $hostname");
$frags{$frag_file} = join (/\n/, @frag_file); $frags{$frag_file} = join (/\n/, @frag_file);
} }
close (FRAGS); close (FRAGS);
} }
@ -436,13 +469,13 @@ if ($? == 0) {
do_log ("INFO: syntax check of sudo fragments is OK on $hostname"); do_log ("INFO: syntax check of sudo fragments is OK on $hostname");
unlink $sudo_file; unlink $sudo_file;
} else { } else {
do_log "ERROR: visudo check failed: ".join ("\n", @syntax_check)." [$hostname]" do_log "ERROR: visudo check failed: ".join ("\n", @syntax_check)." [$hostname]"
and exit(1); and exit(1);
} }
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# read grant definitions # read grant definitions
# result: @grants (array): fragments for which grants have been defined # result: @grants (array): fragments for which grants have been defined
# for this server. # for this server.
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -453,7 +486,7 @@ open (GRANTS, "<", "${run_dir}/grants")
while (<GRANTS>) { while (<GRANTS>) {
my ($what, $where, @what, @where); my ($what, $where, @what, @where);
chomp (); chomp ();
next if (/^$/ || /\#/); next if (/^$/ || /\#/);
s/\s+//g; s/\s+//g;
@ -465,10 +498,10 @@ while (<GRANTS>) {
do_log ("WARN: ignoring line $. in 'grants' due to missing/non-resolving values [$hostname]"); do_log ("WARN: ignoring line $. in 'grants' due to missing/non-resolving values [$hostname]");
next; next;
} }
foreach my $grant (sort (@what)) { foreach my $grant (sort (@what)) {
foreach my $server (sort (@where)) { foreach my $server (sort (@where)) {
do_log ("DEBUG: adding grants for $grant on $server in \@grants") do_log ("DEBUG: adding grants for $grant on $server in \@grants")
if ($server eq $hostname); if ($server eq $hostname);
# add sudo fragment to grants list if the entry is for this host # add sudo fragment to grants list if the entry is for this host
push (@grants, $grant) if ($server eq $hostname); push (@grants, $grant) if ($server eq $hostname);
@ -494,7 +527,7 @@ if ($preview && $global) {
while (<GRANTS>) { while (<GRANTS>) {
my ($what, $where, @what, @where); my ($what, $where, @what, @where);
chomp (); chomp ();
next if (/^$/ || /\#/); next if (/^$/ || /\#/);
s/\s+//g; s/\s+//g;
@ -506,15 +539,15 @@ if ($preview && $global) {
do_log ("WARN: ignoring line $. in 'grants' due to missing/non-resolving values [$hostname]"); do_log ("WARN: ignoring line $. in 'grants' due to missing/non-resolving values [$hostname]");
next; next;
} }
foreach my $grant (sort (@what)) { foreach my $grant (sort (@what)) {
foreach my $server (sort (@where)) { foreach my $server (sort (@where)) {
do_log ("$grant|$server") do_log ("$grant|$server")
} }
} }
}; };
close (GRANTS); close (GRANTS);
exit (0); exit (0);
} }
@ -527,48 +560,48 @@ do_log ("INFO: (de)-activating SUDO fragments ....");
# check for SELinux # check for SELinux
unless ($preview) { unless ($preview) {
SWITCH: { SWITCH: {
$os eq "Linux" && do { $os eq "Linux" && do {
$selinux_status = qx#/usr/sbin/getenforce 2>/dev/null#; $selinux_status = qx#/usr/sbin/getenforce 2>/dev/null#;
chomp ($selinux_status); chomp ($selinux_status);
if ($selinux_status eq "Permissive" or $selinux_status eq "Enforcing") { if ($selinux_status eq "Permissive" or $selinux_status eq "Enforcing") {
do_log ("INFO: runtime info: detected active SELinux system on $hostname"); do_log ("INFO: runtime info: detected active SELinux system on $hostname");
$has_selinux = 1; $has_selinux = 1;
} }
last SWITCH; last SWITCH;
}; };
} }
} }
# remove previous fragment files first # remove previous fragment files first
opendir (FRAGS_DIR, "${fragments_dir}") opendir (FRAGS_DIR, "${fragments_dir}")
or do_log ("ERROR: cannot open ${fragments_dir} directory [$! $hostname]") or do_log ("ERROR: cannot open ${fragments_dir} directory [$! $hostname]")
and exit (1); and exit (1);
while (my $frag_file = readdir (FRAGS_DIR)) { while (my $frag_file = readdir (FRAGS_DIR)) {
next if ($frag_file =~ /^\./ or $frag_file eq $immutable_self_file); next if ($frag_file =~ /^\./ or $frag_file eq $immutable_self_file);
# safe to ignore . (dot) files as sudo also does as well # safe to ignore . (dot) files as sudo also does as well
unless ($preview) { unless ($preview) {
my $frag_file = "$fragments_dir/$frag_file"; my $frag_file = "$fragments_dir/$frag_file";
if (unlink ($frag_file)) { if (unlink ($frag_file)) {
do_log ("INFO: de-activating fragment file $frag_file on $hostname"); do_log ("INFO: de-activating fragment file $frag_file on $hostname");
} else { } else {
do_log ("ERROR: cannot de-activate fragment file(s) [$! $hostname]"); do_log ("ERROR: cannot de-activate fragment file(s) [$! $hostname]");
exit (1); exit (1);
} }
} }
} }
closedir (FRAGS_DIR); closedir (FRAGS_DIR);
# re-active current fragments # re-active current fragments
foreach my $grant (@grants) { foreach my $grant (@grants) {
# do not create empty sudo files # do not create empty sudo files
if (exists ($frags{$grant})) { if (exists ($frags{$grant})) {
my $sudo_file = "$fragments_dir/$grant"; my $sudo_file = "$fragments_dir/$grant";
unless ($preview) { unless ($preview) {
open (SUDO_FILE, "+>", $sudo_file) open (SUDO_FILE, "+>", $sudo_file)
or do_log ("ERROR: cannot open file for writing in $fragments_dir [$! $hostname]") or do_log ("ERROR: cannot open file for writing in $fragments_dir [$! $hostname]")
@ -577,21 +610,21 @@ foreach my $grant (@grants) {
print SUDO_FILE "$frags{$grant}\n" unless $preview; print SUDO_FILE "$frags{$grant}\n" unless $preview;
do_log ("INFO: activating fragment $grant on $hostname"); do_log ("INFO: activating fragment $grant on $hostname");
close (SUDO_FILE) unless $preview; close (SUDO_FILE) unless $preview;
# set permissions to world readable & SELinux contexts # set permissions to world readable & SELinux contexts
unless ($preview) { unless ($preview) {
SWITCH: { SWITCH: {
$os eq "HP-UX" && do { $os eq "HP-UX" && do {
set_file ($sudo_file, 0440, 2, 2); set_file ($sudo_file, 0440, 2, 2);
last SWITCH; last SWITCH;
}; };
$os eq "Linux" && do { $os eq "Linux" && do {
if ($has_selinux) { if ($has_selinux) {
system ("/usr/bin/chcon -t $selinux_context $sudo_file") == 0 or system ("/usr/bin/chcon -t $selinux_context $sudo_file") == 0 or
do_log ("WARN: failed to set SELinux context $selinux_context on $sudo_file [$hostname]"); do_log ("WARN: failed to set SELinux context $selinux_context on $sudo_file [$hostname]");
} }
set_file ($sudo_file, 0440, 0, 0); set_file ($sudo_file, 0440, 0, 0);
last SWITCH; last SWITCH;
}; };
} }
} }
@ -613,20 +646,20 @@ unless ($preview) {
print SELF_FILE $immutable_self_cmd."\n"; print SELF_FILE $immutable_self_cmd."\n";
do_log ("INFO: activating immutable self fragment $immutable_self_file on $hostname"); do_log ("INFO: activating immutable self fragment $immutable_self_file on $hostname");
SWITCH: { SWITCH: {
$os eq "HP-UX" && do { $os eq "HP-UX" && do {
set_file ($self_file, 0440, 2, 2); set_file ($self_file, 0440, 2, 2);
last SWITCH; last SWITCH;
}; };
$os eq "Linux" && do { $os eq "Linux" && do {
if ($has_selinux) { if ($has_selinux) {
system ("/usr/bin/chcon -t $selinux_context $self_file") == 0 or system ("/usr/bin/chcon -t $selinux_context $self_file") == 0 or
do_log ("WARN: failed to set SELinux context $selinux_context on $self_file [$hostname]"); do_log ("WARN: failed to set SELinux context $selinux_context on $self_file [$hostname]");
} }
set_file ($self_file, 0440, 0, 0); set_file ($self_file, 0440, 0, 0);
last SWITCH; last SWITCH;
}; };
} }
close (SELF_FILE); close (SELF_FILE);
} }
exit (0); exit (0);
@ -647,20 +680,20 @@ update_sudo.pl - distributes SUDO fragments according to a desired state model.
=head1 SYNOPSIS =head1 SYNOPSIS
update_sudo.pl [-d|--debug] update_sudo.pl [-d|--debug]
[-h|--help] [-h|--help]
([-p|--preview] [-g|--global]) ([-p|--preview] [-g|--global])
[-v|--verbose] [-v|--verbose]
[-V|--version] [-V|--version]
=head1 DESCRIPTION =head1 DESCRIPTION
B<update_sudo.pl> distributes SUDO fragments into the C<$fragments_dir> repository based on the F<grants>, F<alias> and F<fragments> files. B<update_sudo.pl> distributes SUDO fragments into the C<$fragments_dir> repository based on the F<grants>, F<alias> and F<fragments> files.
This script should be run on each host where SUDO is the required method of privilege escalation. This script should be run on each host where SUDO is the required method of privilege escalation.
For update SUDO fragments must be stored in a generic F<fragments> file within the same directory as B<update_sudo.pl> script. For update SUDO fragments must be stored in a generic F<fragments> file within the same directory as B<update_sudo.pl> script.
Alternatively SUDO fragments may be stored as set of individual files within a called sub-directory called F<fragments.d>. Alternatively SUDO fragments may be stored as set of individual files within a called sub-directory called F<fragments.d>.
Both methods are mutually exclusive and the latter always take precedence. Both methods are mutually exclusive and the latter always take precedence.
=head1 CONFIGURATION =head1 CONFIGURATION
@ -673,7 +706,7 @@ B<update_sudo.pl> requires the presence of at least one of the following configu
=item * F<update_sudo.conf.local> =item * F<update_sudo.conf.local>
=back =back
Use F<update_sudo.conf.local> for localized settings per host. Settings in the localized configuration file will always override other values. Use F<update_sudo.conf.local> for localized settings per host. Settings in the localized configuration file will always override other values.
@ -714,12 +747,12 @@ S< >Must be used in conjunction with the --preview option. This will dump
=item -v | --verbose =item -v | --verbose
S< >Be verbose during exection. S< >Be verbose during exection.
=item -V | --version =item -V | --version
S< >Show version of the script. S< >Show version of the script.
=back =back
=head1 NOTES =head1 NOTES
@ -729,20 +762,8 @@ S< >Show version of the script.
=item * Options may be bundled (e.g. -vp) =item * Options may be bundled (e.g. -vp)
=back =back
=head1 AUTHOR =head1 AUTHOR
(c) KUDOS BVBA, Patrick Van der Veken (c) KUDOS BVBA, Patrick Van der Veken
=head1 HISTORY
@(#) 2014-12-04: VRF 1.0.0: first version [Patrick Van der Veken]
@(#) 2014-12-16: VRF 1.0.1: added SELinux context [Patrick Van der Veken]
@(#) 2014-12-16: VRF 1.0.2: fixed a problem with the immutable self fragment code [Patrick Van der Veken]
@(#) 2015-02-02: VRF 1.0.3: changed 'basename' into 'fileparse' call to support fragment files with extensions [Patrick Van der Veken]
@(#) 2015-08-18: VRF 1.1.0: replace uname/hostname syscalls, now support for FQDN via $use_fqdn, other fixes [Patrick Van der Veken]
@(#) 2015-08-26: VRF 1.1.1: small and not so small fixes [Patrick Van der Veken]
@(#) 2015-08-27: VRF 1.1.2: small fix [Patrick Van der Veken]
@(#) 2015-09-09: VRF 1.1.3: small selinux fix [Patrick Van der Veken]
@(#) 2015-09-09: VRF 1.1.4: wrong handling of RC=0 in system() [Patrick Van der Veken]