* Add flag ignore_errors to allow uninterrupted fragment deployment
* Other minor updates
This commit is contained in:
parent
813315bc4f
commit
78d2d6aff1
@ -2,9 +2,8 @@
|
|||||||
|
|
||||||
## What's new
|
## What's new
|
||||||
|
|
||||||
:loudspeaker: **30/12/2020**:
|
:loudspeaker: **27/04/2025**:
|
||||||
* added support for SELinux (CentOS/RHEL 8.x)
|
* added the `ignore_errors` flag to allow uninterrupted deployment of fragements.
|
||||||
* various fixes
|
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#******************************************************************************
|
#******************************************************************************
|
||||||
# @(#) manage_sudo.sh
|
# @(#) manage_sudo.sh
|
||||||
#******************************************************************************
|
#******************************************************************************
|
||||||
# @(#) Copyright (C) 2014 by KUDOS BVBA (info@kudos.be). All rights reserved.
|
# @(#) Copyright (C) 2014 by KUDOS BV (info@kudos.be). All rights reserved.
|
||||||
#
|
#
|
||||||
# This program is a free software; you can redistribute it and/or modify
|
# This program is a free software; you can redistribute it and/or modify
|
||||||
# it under the same terms of the GNU General Public License as published by
|
# it under the same terms of the GNU General Public License as published by
|
||||||
@ -42,7 +42,7 @@
|
|||||||
# or LOCAL_CONFIG_FILE instead
|
# or LOCAL_CONFIG_FILE instead
|
||||||
|
|
||||||
# define the version (YYYY-MM-DD)
|
# define the version (YYYY-MM-DD)
|
||||||
typeset -r SCRIPT_VERSION="2021-06-17"
|
typeset -r SCRIPT_VERSION="2025-04-27"
|
||||||
# name of the global configuration file (script)
|
# name of the global configuration file (script)
|
||||||
typeset -r GLOBAL_CONFIG_FILE="manage_sudo.conf"
|
typeset -r GLOBAL_CONFIG_FILE="manage_sudo.conf"
|
||||||
# name of the local configuration file (script)
|
# name of the local configuration file (script)
|
||||||
@ -585,7 +585,7 @@ function display_usage
|
|||||||
cat << EOT
|
cat << EOT
|
||||||
|
|
||||||
**** ${SCRIPT_NAME} ****
|
**** ${SCRIPT_NAME} ****
|
||||||
**** (c) KUDOS BVBA - Patrick Van der Veken ****
|
**** (c) KUDOS BV - Patrick Van der Veken ****
|
||||||
|
|
||||||
Performs basic functions for SUDO controls: update SUDOers files locally or
|
Performs basic functions for SUDO controls: update SUDOers files locally or
|
||||||
remote, validate SUDO syntax or copy/distribute the SUDO controls files
|
remote, validate SUDO syntax or copy/distribute the SUDO controls files
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
# use short hostnames or FQDN (0=short names; 1=FQDN) [default: 0]
|
# use short hostnames or FQDN (0=short names; 1=FQDN) [default: 0]
|
||||||
use_fqdn=1
|
use_fqdn=1
|
||||||
|
|
||||||
|
# ignore errors during fragment deployment (0=no; 1=yes [default: 0])
|
||||||
|
ignore_errors=0
|
||||||
|
|
||||||
# target directory for sudo fragment files
|
# target directory for sudo fragment files
|
||||||
fragments_dir=/etc/sudo_controls/sudoers.d
|
fragments_dir=/etc/sudo_controls/sudoers.d
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#******************************************************************************
|
#******************************************************************************
|
||||||
# @(#) update_sudo.pl
|
# @(#) update_sudo.pl
|
||||||
#******************************************************************************
|
#******************************************************************************
|
||||||
# @(#) Copyright (C) 2014 by KUDOS BVBA <info@kudos.be>. All rights reserved.
|
# @(#) Copyright (C) 2014 by KUDOS BV <info@kudos.be>. All rights reserved.
|
||||||
#
|
#
|
||||||
# This program is a free software; you can redistribute it and/or modify
|
# This program is a free software; you can redistribute it and/or modify
|
||||||
# it under the same terms of the GNU General Public License as published by
|
# it under the same terms of the GNU General Public License as published by
|
||||||
@ -44,7 +44,7 @@ use File::Temp qw(tempfile);
|
|||||||
|
|
||||||
# ------------------------- CONFIGURATION starts here -------------------------
|
# ------------------------- CONFIGURATION starts here -------------------------
|
||||||
# define the version (YYYY-MM-DD)
|
# define the version (YYYY-MM-DD)
|
||||||
my $script_version = "2020-12-30";
|
my $script_version = "2025-04-27";
|
||||||
# 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)
|
||||||
@ -55,7 +55,7 @@ my $max_recursion = 5;
|
|||||||
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, $ignore_errors) = (0,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);
|
||||||
@ -89,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>) {
|
||||||
@ -102,6 +102,10 @@ sub parse_config_file {
|
|||||||
$use_fqdn = $1;
|
$use_fqdn = $1;
|
||||||
do_log ("DEBUG: picking up setting: use_fqdn=${use_fqdn}");
|
do_log ("DEBUG: picking up setting: use_fqdn=${use_fqdn}");
|
||||||
}
|
}
|
||||||
|
if (/^\s*ignore_errors\s*=\s*(0|1)\s*$/) {
|
||||||
|
$ignore_errors = $1;
|
||||||
|
do_log ("DEBUG: picking up setting: ignore_errors=${ignore_errors}");
|
||||||
|
}
|
||||||
if (/^\s*fragments_dir\s*=\s*([0-9A-Za-z_\-\.\/~]+)\s*$/) {
|
if (/^\s*fragments_dir\s*=\s*([0-9A-Za-z_\-\.\/~]+)\s*$/) {
|
||||||
$fragments_dir = $1;
|
$fragments_dir = $1;
|
||||||
do_log ("DEBUG: picking up setting: fragments_dir=${fragments_dir}");
|
do_log ("DEBUG: picking up setting: fragments_dir=${fragments_dir}");
|
||||||
@ -156,12 +160,24 @@ sub set_file {
|
|||||||
|
|
||||||
my ($file, $perm, $uid, $gid) = @_;
|
my ($file, $perm, $uid, $gid) = @_;
|
||||||
|
|
||||||
chmod ($perm, "$file")
|
my $rc = chmod ($perm, "$file");
|
||||||
or do_log ("ERROR: cannot set permissions on $file [$! $hostname]")
|
if (!$rc) {
|
||||||
and exit (1);
|
if ($ignore_errors) {
|
||||||
chown ($uid, $gid, "$file")
|
do_log ("ERROR: cannot set permissions on $file [$!/$hostname] -- IGNORED");
|
||||||
or do_log ("ERROR: cannot set ownerships on $file [$! $hostname]")
|
} else {
|
||||||
and exit (1);
|
do_log ("ERROR: cannot set permissions on $file [$!/$hostname]");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
my $rc = chown ($uid, $gid, "$file");
|
||||||
|
if (!$rc) {
|
||||||
|
if ($ignore_errors) {
|
||||||
|
do_log ("ERROR: cannot set ownerships on $file [$!/$hostname] -- IGNORED");
|
||||||
|
} else {
|
||||||
|
do_log ("ERROR: cannot set ownerships on $file [$!/$hostname]");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
@ -182,6 +198,7 @@ if ( @ARGV > 0 ) {
|
|||||||
debug|d
|
debug|d
|
||||||
help|h|?
|
help|h|?
|
||||||
global|g
|
global|g
|
||||||
|
ignore|i
|
||||||
preview|p
|
preview|p
|
||||||
verbose|v
|
verbose|v
|
||||||
version|V
|
version|V
|
||||||
@ -204,6 +221,10 @@ if ($options{'help'}) {
|
|||||||
if ($options{'global'}) {
|
if ($options{'global'}) {
|
||||||
$global = 1;
|
$global = 1;
|
||||||
}
|
}
|
||||||
|
# check ignore parameter
|
||||||
|
if ($options{'ignore'}) {
|
||||||
|
$ignore_errors = 1;
|
||||||
|
}
|
||||||
# check preview parameter
|
# check preview parameter
|
||||||
if ($options{'preview'}) {
|
if ($options{'preview'}) {
|
||||||
$preview = 1;
|
$preview = 1;
|
||||||
@ -292,7 +313,7 @@ do_log ("INFO: runtime info: ".getpwuid ($<)."; ${hostname}\@${run_dir}; Perl v$
|
|||||||
do_log ("INFO: reading 'alias' file ...");
|
do_log ("INFO: reading 'alias' file ...");
|
||||||
|
|
||||||
open (ALIASES, "<", "${run_dir}/alias")
|
open (ALIASES, "<", "${run_dir}/alias")
|
||||||
or do_log ("ERROR: cannot read 'alias' file [$! $hostname]") and exit (1);
|
or do_log ("ERROR: cannot read 'alias' file [$!/$hostname]") and exit (1);
|
||||||
while (<ALIASES>) {
|
while (<ALIASES>) {
|
||||||
|
|
||||||
my ($key, $value, @values);
|
my ($key, $value, @values);
|
||||||
@ -370,7 +391,7 @@ 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 =~ /^\./);
|
||||||
@ -388,7 +409,7 @@ if (-d "${run_dir}/fragments.d") {
|
|||||||
# 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");
|
||||||
|
|
||||||
@ -482,7 +503,7 @@ if ($? == 0) {
|
|||||||
do_log ("INFO: reading 'grants' file ...");
|
do_log ("INFO: reading 'grants' file ...");
|
||||||
|
|
||||||
open (GRANTS, "<", "${run_dir}/grants")
|
open (GRANTS, "<", "${run_dir}/grants")
|
||||||
or do_log ("ERROR: cannot read 'grants' file [$! $hostname]") and exit (1);
|
or do_log ("ERROR: cannot read 'grants' file [$!/$hostname]") and exit (1);
|
||||||
while (<GRANTS>) {
|
while (<GRANTS>) {
|
||||||
|
|
||||||
my ($what, $where, @what, @where);
|
my ($what, $where, @what, @where);
|
||||||
@ -523,7 +544,7 @@ print Dumper(\@grants) if $debug;
|
|||||||
if ($preview && $global) {
|
if ($preview && $global) {
|
||||||
|
|
||||||
open (GRANTS, "<", "${run_dir}/grants")
|
open (GRANTS, "<", "${run_dir}/grants")
|
||||||
or do_log ("ERROR: cannot read 'grants' file [$! $hostname]") and exit (1);
|
or do_log ("ERROR: cannot read 'grants' file [$!/$hostname]") and exit (1);
|
||||||
while (<GRANTS>) {
|
while (<GRANTS>) {
|
||||||
|
|
||||||
my ($what, $where, @what, @where);
|
my ($what, $where, @what, @where);
|
||||||
@ -574,7 +595,7 @@ unless ($preview) {
|
|||||||
|
|
||||||
# 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);
|
||||||
@ -587,7 +608,7 @@ while (my $frag_file = readdir (FRAGS_DIR)) {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -604,7 +625,7 @@ foreach my $grant (@grants) {
|
|||||||
|
|
||||||
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]")
|
||||||
and exit (1);
|
and exit (1);
|
||||||
}
|
}
|
||||||
print SUDO_FILE "$frags{$grant}\n" unless $preview;
|
print SUDO_FILE "$frags{$grant}\n" unless $preview;
|
||||||
@ -639,7 +660,7 @@ unless ($preview) {
|
|||||||
my $self_file = "$fragments_dir/$immutable_self_file";
|
my $self_file = "$fragments_dir/$immutable_self_file";
|
||||||
|
|
||||||
open (SELF_FILE, "+>", $self_file)
|
open (SELF_FILE, "+>", $self_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]")
|
||||||
and exit (1);
|
and exit (1);
|
||||||
|
|
||||||
print SELF_FILE "# THIS IS THE IMMUTABLE SELF FRAGMENT OF SUDO CONTROLS\n";
|
print SELF_FILE "# THIS IS THE IMMUTABLE SELF FRAGMENT OF SUDO CONTROLS\n";
|
||||||
@ -682,6 +703,7 @@ update_sudo.pl - distributes SUDO fragments according to a desired state model.
|
|||||||
|
|
||||||
update_sudo.pl [-d|--debug]
|
update_sudo.pl [-d|--debug]
|
||||||
[-h|--help]
|
[-h|--help]
|
||||||
|
[-i|--ignore]
|
||||||
([-p|--preview] [-g|--global])
|
([-p|--preview] [-g|--global])
|
||||||
[-v|--verbose]
|
[-v|--verbose]
|
||||||
[-V|--version]
|
[-V|--version]
|
||||||
@ -716,6 +738,8 @@ Following settings must be configured:
|
|||||||
|
|
||||||
=item * B<use_fqdn> : whether to use short or FQDN host names
|
=item * B<use_fqdn> : whether to use short or FQDN host names
|
||||||
|
|
||||||
|
=item * B<ignore_errors> : whether to ignore errors during fragment deployment
|
||||||
|
|
||||||
=item * B<fragments_dir> : target directory for SUDO fragments files
|
=item * B<fragments_dir> : target directory for SUDO fragments files
|
||||||
|
|
||||||
=item * B<visudo_bin> : path to the visudo tool (for sudo rules syntax checking)
|
=item * B<visudo_bin> : path to the visudo tool (for sudo rules syntax checking)
|
||||||
@ -736,6 +760,10 @@ S< >Be I<very> verbose during execution; show array/hash dumps.
|
|||||||
|
|
||||||
S< >Show the help page.
|
S< >Show the help page.
|
||||||
|
|
||||||
|
=item -i | --ignore
|
||||||
|
|
||||||
|
S< >Ignore errors during fragment deployment.
|
||||||
|
|
||||||
=item -p | --preview
|
=item -p | --preview
|
||||||
|
|
||||||
S< >Do not actually distribute any SUDO fragments, nor update/remove SUDO files.
|
S< >Do not actually distribute any SUDO fragments, nor update/remove SUDO files.
|
||||||
@ -766,4 +794,4 @@ S< >Show version of the script.
|
|||||||
|
|
||||||
=head1 AUTHOR
|
=head1 AUTHOR
|
||||||
|
|
||||||
(c) KUDOS BVBA, Patrick Van der Veken
|
(c) KUDOS BV, Patrick Van der Veken
|
||||||
|
Loading…
x
Reference in New Issue
Block a user