Various updates

manage_sudo.sh: moved essential configuration items of the script into a
separate configuration file (global/local), fix in wait_for_children
(VRF 1.2.0) [Patrick Van der Veken]
update_sudo.pl: VRF 1.1.0: replace uname/hostname syscalls, now support
for FQDN via $use_fqdn, other fixes [Patrick Van der Veken]
Other fixes and cleanups
This commit is contained in:
Patrick Van der Veken 2015-08-18 07:59:22 +02:00
parent 389aacac9b
commit 7726d1579c
5 changed files with 1301 additions and 58 deletions

52
manage_sudo.conf Normal file
View File

@ -0,0 +1,52 @@
#******************************************************************************
# manage_ssh.sh configuration file
#******************************************************************************
#
# Lines starting with '#' (hash) are comment lines
#
# Format: option=<value>
#
# Use double or single quotes around the option values in case of strings.
#
# name of the user account performing the SUDO controls copies
# (leave blank for current user)
SUDO_TRANSFER_USER=""
# name of the OS group that should own the SUDO controls files
SUDO_OWNER_GROUP="sudoadmin"
# extra arguments/options for the SFTP command
SFTP_ARGS="-o StrictHostKeyChecking=no -o ConnectTimeout=10 -b - "
# extra arguments/options for the SSH command
SSH_ARGS="-o StrictHostKeyChecking=no -o ConnectTimeout=10 -n"
# location of the local SUDO controls directory
LOCAL_DIR="/etc/sudo_master"
# location of the remote SUDO controls directory
REMOTE_DIR="/etc/sudo_controls/holding"
# name of the user account performing the SUDO controls update
# (leave blank for current user but user should have remote sudo root privs)
SUDO_UPDATE_USER=""
# options to pass to manage_ssh.sh when executing a key update
SUDO_UPDATE_OPTS="--verbose --remove"
# path to the visudo tool
VISUDO_BIN="/usr/sbin/visudo"
# maximum number of background process to spawn (~maxuprc, ~nstrpty etc)
MAX_BACKGROUND_PROCS=30
# location of the backup directory (for configuration & key files)
BACKUP_DIR="${LOCAL_DIR}/backup"
# location of log directory (default), see --log-dir)
LOG_DIR="/var/log"
#******************************************************************************
# End of FILE
#******************************************************************************

View File

@ -20,10 +20,11 @@
# DOES: performs basic functions for SUDO controls: update SUDOers files locally # DOES: performs basic functions for SUDO controls: update SUDOers files locally
# or remote, validate SUDO syntax, distribute the SUDO fragment files # or remote, validate SUDO syntax, distribute the SUDO fragment files
# EXPECTS: (see --help for more options) # EXPECTS: (see --help for more options)
# REQUIRES: check_config(), check_logging(), check_params(), check_setup(), # REQUIRES: check_config(), check_logging(), check_params(), check_root_user(),
# check_syntax(), count_fields(), die(), display_usage(), # check_setup(), check_syntax(), count_fields(), die(), display_usage(),
# distribute2host(), do_cleanup(), fix2host(), log(), resolve_host(), # distribute2host(), do_cleanup(), fix2host(), log(), resolve_host(),
# sftp_file(), update2host(), validate_syntax(), warn() # sftp_file(), update2host(), validate_syntax(), wait_for_children(),
# warn()
# For other pre-requisites see the documentation in display_usage() # For other pre-requisites see the documentation in display_usage()
# #
# @(#) HISTORY: # @(#) HISTORY:
@ -34,7 +35,9 @@
# @(#) 2015-02-02: allow fragments files to have extensions in merge_fragments() # @(#) 2015-02-02: allow fragments files to have extensions in merge_fragments()
# use 'sudo -n' (VRF 1.1.2) [Patrick Van der Veken] # use 'sudo -n' (VRF 1.1.2) [Patrick Van der Veken]
# @(#) 2015-04-10: fix in --fix-local routine (VRF 1.1.3) [Patrick Van der Veken] # @(#) 2015-04-10: fix in --fix-local routine (VRF 1.1.3) [Patrick Van der Veken]
# @(#) 2015-05-16: added SSH_OWNER_GROUP (VRF 1.1.4) [Patrick Van der Veken] # @(#) 2015-08-18: moved essential configuration items of the script into a
# @(#) separate configuration file (global/local), fix in
# @(#) wait_for_children (VRF 1.2.0) [Patrick Van der Veken]
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# DO NOT CHANGE THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING! # DO NOT CHANGE THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING!
#****************************************************************************** #******************************************************************************
@ -44,32 +47,15 @@
#****************************************************************************** #******************************************************************************
# ------------------------- CONFIGURATION starts here ------------------------- # ------------------------- CONFIGURATION starts here -------------------------
# Below configuration values should not be changed. Use the GLOBAL_CONFIG_FILE
# or LOCAL_CONFIG_FILE instead
# define the V.R.F (version/release/fix) # define the V.R.F (version/release/fix)
MY_VRF="1.1.4" MY_VRF="1.2.0"
# name of the user account performing the SUDO controls copies # name of the global configuration file (script)
# (leave blank for current user) GLOBAL_CONFIG_FILE="manage_sudo.conf"
SUDO_TRANSFER_USER="" # name of the local configuration file (script)
# name of the OS group that should own the SUDO controls files LOCAL_CONFIG_FILE="manage_sudonf.local"
SUDO_OWNER_GROUP="sudoadmin"
# extra arguments/options for the SFTP command
SFTP_ARGS="-o StrictHostKeyChecking=no -o ConnectTimeout=10 -b - "
# extra arguments/options for the SSH command
SSH_ARGS="-o StrictHostKeyChecking=no -o ConnectTimeout=10 -n"
# location of the local SUDO controls directory
LOCAL_DIR="/etc/sudo_controls"
# location of the remote SUDO controls directory
REMOTE_DIR="/etc/sudo_controls/holding"
# name of the user account performing the SUDO controls update
# (leave blank for current user but user should have remote sudo root privs)
SUDO_UPDATE_USER=""
# path to the visudo tool
VISUDO_BIN="/usr/sbin/visudo"
# maximum number of background process to spawn (~maxuprc, ~nstrpty etc)
MAX_BACKGROUND_PROCS=30
# location of the backup directory (for configuration & key files)
BACKUP_DIR="${LOCAL_DIR}/backup"
# location of log directory (default), see --log-dir)
LOG_DIR="/var/log"
# location of temporary working storage # location of temporary working storage
TMP_DIR="/var/tmp" TMP_DIR="/var/tmp"
# ------------------------- CONFIGURATION ends here --------------------------- # ------------------------- CONFIGURATION ends here ---------------------------
@ -324,7 +310,8 @@ if (( ARG_ACTION == 1 || ARG_ACTION == 2 || ARG_ACTION == 4 ))
then then
for FILE in "${LOCAL_DIR}/update_sudo.pl" \ for FILE in "${LOCAL_DIR}/update_sudo.pl" \
"${LOCAL_DIR}/update_sudo.conf" \ "${LOCAL_DIR}/update_sudo.conf" \
"${SCRIPT_DIR}/${SCRIPT_NAME}" "${SCRIPT_DIR}/${SCRIPT_NAME}" \
"${SCRIPT_DIR}/${GLOBAL_CONFIG_FILE}"
do do
if [[ ! -r "${FILE}" ]] if [[ ! -r "${FILE}" ]]
then then
@ -460,6 +447,8 @@ Note 1: distribute and update actions are run in parallel across a maximum of
Note 2: make sure correct 'sudo' rules are setup on the target systems to allow Note 2: make sure correct 'sudo' rules are setup on the target systems to allow
the SUDO controls script to run with elevated privileges. the SUDO controls script to run with elevated privileges.
Note 3: only GLOBAL configuration files will be distributed to target hosts.
EOT EOT
return 0 return 0
@ -486,7 +475,8 @@ for FILE in "${LOCAL_DIR}/grants!660" \
"${LOCAL_DIR}/alias!660" \ "${LOCAL_DIR}/alias!660" \
"${LOCAL_DIR}/update_sudo.pl!770" \ "${LOCAL_DIR}/update_sudo.pl!770" \
"${LOCAL_DIR}/update_sudo.conf!660" \ "${LOCAL_DIR}/update_sudo.conf!660" \
"${SCRIPT_DIR}/${SCRIPT_NAME}!770" "${SCRIPT_DIR}/${SCRIPT_NAME}!770" \
"${SCRIPT_DIR}/${GLOBAL_CONFIG_FILE}!660"
do do
# sftp transfer # sftp transfer
sftp_file ${FILE} ${SERVER} sftp_file ${FILE} ${SERVER}
@ -515,7 +505,7 @@ then
die "failed to merge fragments into the temporary file ${TMP_MERGE_FILE}" die "failed to merge fragments into the temporary file ${TMP_MERGE_FILE}"
fi fi
# sftp transfer # sftp transfer
sftp_file "${TMP_MERGE_FILE}!440" ${SERVER} sftp_file "${TMP_MERGE_FILE}!640" ${SERVER}
COPY_RC=$? COPY_RC=$?
if (( ! COPY_RC )) if (( ! COPY_RC ))
then then
@ -525,7 +515,7 @@ then
fi fi
[[ -d ${TMP_WORK_DIR} ]] && rm -rf ${TMP_WORK_DIR} 2>/dev/null [[ -d ${TMP_WORK_DIR} ]] && rm -rf ${TMP_WORK_DIR} 2>/dev/null
else else
sftp_file "${FRAGS_FILE}!440" ${SERVER} sftp_file "${FRAGS_FILE}!640" ${SERVER}
COPY_RC=$? COPY_RC=$?
if (( ! COPY_RC )) if (( ! COPY_RC ))
then then
@ -683,7 +673,7 @@ OLD_PWD=$(pwd) && cd ${TRANSFER_DIR}
sftp ${SFTP_ARGS} ${SUDO_TRANSFER_USER}@${TRANSFER_HOST} >/dev/null <<EOT sftp ${SFTP_ARGS} ${SUDO_TRANSFER_USER}@${TRANSFER_HOST} >/dev/null <<EOT
cd ${REMOTE_DIR} cd ${REMOTE_DIR}
put ${SOURCE_FILE} put ${SOURCE_FILE}
#chmod ${TRANSFER_PERMS} ${SOURCE_FILE} chmod ${TRANSFER_PERMS} ${SOURCE_FILE}
EOT EOT
SFTP_RC=$? SFTP_RC=$?
@ -747,13 +737,13 @@ do
# the child might have already ended before we get here (caveat emptor) # the child might have already ended before we get here (caveat emptor)
elif $(wait ${PID}) elif $(wait ${PID})
then then
log "child process ${PID} exited" log "child process ${PID} exited [NOK]"
else
log "child process ${PID} exited"
WAIT_ERRORS=$(( WAIT_ERRORS + 1 )) WAIT_ERRORS=$(( WAIT_ERRORS + 1 ))
else
log "child process ${PID} exited [OK]"
fi fi
done done
# break loop if we no child PIDs left # break loop if we have no child PIDs left
(($# > 0)) || break (($# > 0)) || break
sleep 1 # required to avoid race conditions sleep 1 # required to avoid race conditions
done done
@ -884,6 +874,21 @@ do
esac esac
done done
# check for configuration files (local overrides local)
if [[ -r "${SCRIPT_DIR}/${GLOBAL_CONFIG_FILE}" || -r "${SCRIPT_DIR}/${LOCAL_CONFIG_FILE}" ]]
then
if [[ -r "${SCRIPT_DIR}/${GLOBAL_CONFIG_FILE}" ]]
then
. "${SCRIPT_DIR}/${GLOBAL_CONFIG_FILE}"
fi
if [[ -r "${SCRIPT_DIR}/${LOCAL_CONFIG_FILE}" ]]
then
. "${SCRIPT_DIR}/${LOCAL_CONFIG_FILE}"
fi
else
print -u2 "ERROR: could not find global or local configuration file"
fi
# startup checks # startup checks
check_params && check_config && check_setup && check_logging check_params && check_config && check_setup && check_logging
@ -923,7 +928,7 @@ case ${ARG_ACTION} in
then then
# wait until all background processes are completed # wait until all background processes are completed
wait_for_children ${PIDS} || \ wait_for_children ${PIDS} || \
warn "$? background jobs failed to complete correctly" warn "$? background jobs (possibly) failed to complete correctly"
PIDS='' PIDS=''
# reset max updates in background # reset max updates in background
COUNT=${MAX_BACKGROUND_PROCS} COUNT=${MAX_BACKGROUND_PROCS}
@ -931,7 +936,7 @@ case ${ARG_ACTION} in
done done
# final wait for background processes to be finished completely # final wait for background processes to be finished completely
wait_for_children ${PIDS} || \ wait_for_children ${PIDS} || \
warn "$? background jobs failed to complete correctly" warn "$? background jobs (possibly) failed to complete correctly"
log "finished applying SUDO controls remotely" log "finished applying SUDO controls remotely"
;; ;;
@ -962,7 +967,7 @@ case ${ARG_ACTION} in
then then
# wait until all background processes are completed # wait until all background processes are completed
wait_for_children ${PIDS} || \ wait_for_children ${PIDS} || \
warn "$? background jobs failed to complete correctly" warn "$? background jobs (possibly) failed to complete correctly"
PIDS='' PIDS=''
# reset max updates in background # reset max updates in background
COUNT=${MAX_BACKGROUND_PROCS} COUNT=${MAX_BACKGROUND_PROCS}
@ -970,7 +975,7 @@ case ${ARG_ACTION} in
done done
# final wait for background processes to be finished completely # final wait for background processes to be finished completely
wait_for_children ${PIDS} || \ wait_for_children ${PIDS} || \
warn "$? background jobs failed to complete correctly" warn "$? background jobs (possibly) failed to complete correctly"
log "finished copying/distributing SUDO controls" log "finished copying/distributing SUDO controls"
;; ;;
3) # perform syntax checking 3) # perform syntax checking
@ -1012,7 +1017,7 @@ case ${ARG_ACTION} in
;; ;;
4) # apply SUDO controls locally (root user) 4) # apply SUDO controls locally (root user)
log "ACTION: apply SUDO controls locally" log "ACTION: apply SUDO controls locally"
log "$(${LOCAL_DIR}/update_sudo.pl -v)" log "$(${LOCAL_DIR}/update_sudo.pl ${SUDO_UPDATE_OPTS})"
# no error checking possible here due to log(), done in called script # no error checking possible here due to log(), done in called script
log "finished applying SUDO controls locally" log "finished applying SUDO controls locally"
;; ;;
@ -1128,7 +1133,7 @@ case ${ARG_ACTION} in
then then
# wait until all background processes are completed # wait until all background processes are completed
wait_for_children ${PIDS} || \ wait_for_children ${PIDS} || \
warn "$? background jobs failed to complete correctly" warn "$? background jobs (possibly) failed to complete correctly"
PIDS='' PIDS=''
# reset max updates in background # reset max updates in background
COUNT=${MAX_BACKGROUND_PROCS} COUNT=${MAX_BACKGROUND_PROCS}
@ -1136,11 +1141,11 @@ case ${ARG_ACTION} in
done done
# final wait for background processes to be finished completely # final wait for background processes to be finished completely
wait_for_children ${PIDS} || \ wait_for_children ${PIDS} || \
warn "$? background jobs failed to complete correctly" warn "$? background jobs (possibly) failed to complete correctly"
log "finished applying fixes to the remote SUDO control repository" log "finished applying fixes to the remote SUDO control repository"
;; ;;
7) # dump the configuration namespace 7) # dump the configuration namespace
log "ACTION: dumping the global grant namespace with resolved aliases ..." log "ACTION: dumping the global grants namespace with resolved aliases ..."
${LOCAL_DIR}/update_sudo.pl --preview --global ${LOCAL_DIR}/update_sudo.pl --preview --global
log "finished dumping the global namespace" log "finished dumping the global namespace"
;; ;;

1178
manage_sudo.sh.bak Normal file

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,9 @@
# Do not use double or single quotes around the option values # Do not use double or single quotes around the option values
# #
# use short hostnames or FQDN (0=short names; 1=FQDN) [default: 0]
use_fqdn=1
# 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

View File

@ -29,6 +29,8 @@
#****************************************************************************** #******************************************************************************
use strict; use strict;
use Net::Domain qw(hostfqdn hostname);
use POSIX qw(uname);
use Data::Dumper; use Data::Dumper;
use Getopt::Long; use Getopt::Long;
use Pod::Usage; use Pod::Usage;
@ -42,7 +44,7 @@ use File::Temp qw(tempfile);
# ------------------------- CONFIGURATION starts here ------------------------- # ------------------------- CONFIGURATION starts here -------------------------
# define the V.R.F (version/release/fix) # define the V.R.F (version/release/fix)
my $MY_VRF = "1.0.3"; my $MY_VRF = "1.1.0";
# 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)
@ -51,7 +53,7 @@ my $local_config_file = "update_sudo.conf.local";
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) = (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, %aliases, %frags, @grants); my (%options, %aliases, %frags, @grants);
my ($os, $host, $hostname, $run_dir); my ($os, $host, $hostname, $run_dir);
@ -85,8 +87,8 @@ 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]") and \ do_log ("ERROR: failed to open the configuration file ${config_file} [$! $hostname]")
exit (1); and exit (1);
} }
while (<CONF_FD>) { while (<CONF_FD>) {
chomp (); chomp ();
@ -94,6 +96,10 @@ sub parse_config_file {
if (/^\s*$/ || /^#/) { if (/^\s*$/ || /^#/) {
next; next;
} else { } else {
if (/^\s*use_fqdn\s*=\s*([0-9]+)\s*$/) {
$use_fqdn = $1;
do_log ("DEBUG: picking up setting: use_fqdn=${use_fqdn}");
}
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}");
@ -226,12 +232,10 @@ unless ($preview and $global) {
} }
} }
# where am I? # where am I?
$host = `hostname`; unless ($use_fqdn) {
chomp ($host); $hostname = hostfqdn();
if ($host =~ /\./) {
($hostname) = $host =~ /(.*?)\./;
} else { } else {
$hostname = $host; $hostname = hostname();
} }
$0 =~ /^(.+[\\\/])[^\\\/]+[\\\/]*$/; $0 =~ /^(.+[\\\/])[^\\\/]+[\\\/]*$/;
my $run_dir = $1 || "."; my $run_dir = $1 || ".";
@ -733,3 +737,4 @@ S< >Show version of the script.
@(#) 2014-12-16: VRF 1.0.1: added SELinux context [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] @(#) 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-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]