added --slave option, 3 new configuration parameters & supporting functions for master->slave operations, several bug fixes including sudoers.d ownerships on HP-UX (VRF 1.5.0) [Patrick Van der Veken]

This commit is contained in:
patvdv 2015-10-03 20:04:23 +02:00
parent 2a878a12bb
commit e38facb5d9
2 changed files with 394 additions and 42 deletions

View File

@ -48,6 +48,16 @@ SSH_KEYSCAN_BIN="/usr/bin/ssh-keyscan"
# by default -f <file> is used by manage_sudo.sh to supply hostnames, do not add here
SSH_KEYSCAN_ARGS="-t rsa"
# whether to start an SSH agent process for the master->client operations [0=No; 1=Yes]
DO_SSH_AGENT=0
# whether to start an SSH agent process for the master->slave->client operations [0=No; 1=Yes]
DO_SSH_SLAVE_AGENT=0
# location of the SSH private key that should be added to the SSH agent process
# must be a passphrase-less key (required when using DO_SSH_AGENT, DO_SSH_SLAVE_AGENT)
SSH_PRIVATE_KEY="$HOME/.ssh/id_rsa"
# maximum number of background process to spawn (~maxuprc, ~nstrpty etc)
MAX_BACKGROUND_PROCS=30

View File

@ -2,7 +2,7 @@
#******************************************************************************
# @(#) manage_sudo.sh
#******************************************************************************
# @(#) Copyright (C) 2014 by KUDOS BVBA <info@kudos.be>. All rights reserved.
# @(#) Copyright (C) 2014 by KUDOS BVBA (info@kudos.be). All rights reserved.
#
# 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
@ -18,13 +18,15 @@
# -----------------------------------------------------------------------------
# @(#) MAIN: manage_sudo.sh
# 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)
# REQUIRES: check_config(), check_logging(), check_params(), check_root_user(),
# check_setup(), check_syntax(), count_fields(), die(), display_usage(),
# distribute2host(), do_cleanup(), fix2host(), log(), logc(),
# resolve_host(), sftp_file(), update2host(), validate_syntax(),
# wait_for_children(), warn()
# distribute2host(), distribute2slave(), do_cleanup(), fix2host(),
# fix2slave(), get_linux_name(), get_linux_version(), log(), logc(),
# resolve_host(), sftp_file(), start_ssh_agent(), stop_ssh_agent(),
# update2host(), update2slave(), validate_syntax(), wait_for_children(),
# warn()
# For other pre-requisites see the documentation in display_usage()
#
# @(#) HISTORY:
@ -54,6 +56,9 @@
# @(#) (VRF 1.3.3) [Patrick Van der Veken]
# @(#) 2015-09-27: added SSH host keys discovery, re-assigned '-d' command-line
# @(#) option to this function (VRF 1.4.0) [Patrick Van der Veken]
# @(#) 2015-10-03: added --slave option, 3 new configuration parameters & supporting
# @(#) functions for master->slave operations, several bug fixes including
# @(#) sudoers.d ownerships on HP-UX (VRF 1.5.0) [Patrick Van der Veken]
# -----------------------------------------------------------------------------
# DO NOT CHANGE THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING!
#******************************************************************************
@ -67,7 +72,7 @@
# or LOCAL_CONFIG_FILE instead
# define the V.R.F (version/release/fix)
MY_VRF="1.4.0"
MY_VRF="1.5.0"
# name of the global configuration file (script)
GLOBAL_CONFIG_FILE="manage_sudo.conf"
# name of the local configuration file (script)
@ -80,13 +85,16 @@ PATH=${PATH}:/usr/bin:/usr/local/bin
SCRIPT_NAME=$(basename $0)
SCRIPT_DIR=$(dirname $0)
OS_NAME="$(uname)"
HOST_NAME="$(hostname)"
FRAGS_FILE=""
FRAGS_DIR=""
TARGETS_FILE=""
DO_SLAVE=0
FIX_CREATE=0
CAN_CHECK_SYNTAX=1
CAN_DISCOVER_KEYS=1
CAN_REMOVE_TEMP=1
CAN_START_AGENT=1
TMP_FILE="${TMP_DIR}/.${SCRIPT_NAME}.$$"
TMP_RC_FILE="${TMP_DIR}/.${SCRIPT_NAME}.rc.$$"
# command-line parameters
@ -158,6 +166,18 @@ then
print -u2 "ERROR: no value for the SSH_KEYSCAN_BIN setting in the configuration file"
exit 1
fi
# DO_SSH_AGENT
if [[ -z "${DO_SSH_AGENT}" ]]
then
print -u2 "ERROR:no value for the DO_SSH_AGENT setting in the configuration file"
exit 1
fi
# DO_SSH_SLAVE_AGENT
if [[ -z "${DO_SSH_SLAVE_AGENT}" ]]
then
print -u2 "ERROR:no value for the DO_SSH_SLAVE_AGENT setting in the configuration file"
exit 1
fi
# MAX_BACKGROUND_PROCS
if [[ -z "${MAX_BACKGROUND_PROCS}" ]]
then
@ -244,6 +264,15 @@ then
REMOTE_DIR="${ARG_REMOTE_DIR}"
fi
fi
# --slave
if (( DO_SLAVE ))
then
# requires a list of targets (=slave servers)
[[ -n "${ARG_TARGETS}" ]] || {
print -u2 "ERROR: you must specify a list of targets with the --slave option"
exit 1
}
fi
# --targets
if [[ -n "${ARG_TARGETS}" ]]
then
@ -294,19 +323,18 @@ do
exit 1
fi
done
# check for basic SUDO control file(s): targets, /var/tmp/targets.$USER (or $TMP_FILE)
# check for basic SUDO control file(s): targets (or $TMP_FILE)
if (( ARG_ACTION == 1 || ARG_ACTION == 2 || ARG_ACTION == 6 || ARG_ACTION == 10 ))
then
if [[ -z "${ARG_TARGETS}" ]]
then
TARGETS_FILE="${LOCAL_DIR}/targets"
if [ \( ! -r "${TARGETS_FILE}" \) -a \( ! -r "/var/tmp/targets.${USER}" \) ]
if [[ ! -r "${TARGETS_FILE}" ]]
then
print -u2 "ERROR: cannot read file ${TARGETS_FILE} nor /var/tmp/targets.${USER}"
print -u2 "ERROR: cannot read file ${TARGETS_FILE}"
print -u2 "ERROR: possibly this is not a master or slave server"
exit 1
fi
# override default targets file
[[ -r "/var/tmp/targets.${USER}" ]] && TARGETS_FILE="/var/tmp/targets.${USER}"
else
TARGETS_FILE=${TMP_FILE}
fi
@ -363,6 +391,23 @@ then
print -u2 "WARN: 'ssh-keyscan' tool not found, host key discovery is not possible"
CAN_DISCOVER_KEYS=0
fi
# check for SSH agent pre-requisites
if (( DO_SSH_AGENT || DO_SSH_SLAVE_AGENT ))
then
# ssh-agent
which ssh-agent 2>/dev/null
if (( $? ))
then
print -u2 "WARN: ssh-agent not available on ${HOST_NAME}"
CAN_START_AGENT=0
fi
# private key
if [[ ! -r "${SSH_PRIVATE_KEY}" ]]
then
print -u2 "WARN: SSH private key not found ${SSH_PRIVATE_KEY}, ssh-agent disabled"
CAN_START_AGENT=0
fi
fi
return 0
}
@ -464,13 +509,11 @@ Performs basic functions for SUDO controls: update SUDOers files locally or
remote, validate SUDO syntax or copy/distribute the SUDO controls files
Syntax: ${SCRIPT_DIR}/${SCRIPT_NAME} [--help] | (--backup | --check-syntax | --check-sudo | --preview-global | --update) |
(--apply [--remote-dir=<remote_directory>] [--targets=<host1>,<host2>,...]) |
((--copy|--distribute) [--remote-dir=<remote_directory> [--targets=<host1>,<host2>,...]]) |
(--apply [--slave] [--remote-dir=<remote_directory>] [--targets=<host1>,<host2>,...]) |
((--copy|--distribute) [--slave] [--remote-dir=<remote_directory> [--targets=<host1>,<host2>,...]]) |
(--discover [--targets=<host1>,<host2>,...]) |
([--fix-local --fix-dir=<repository_dir> [--create-dir]] | [--fix-remote [--create-dir] [--targets=<host1>,<host2>,...]])
[--preview-global] [--local-dir=<local_directory>]
[--no-log] [--log-dir=<log_directory>] [--debug]
([--fix-local --fix-dir=<repository_dir> [--create-dir]] | [--fix-remote [--slave] [--create-dir] [--targets=<host1>,<host2>,...]])
[--local-dir=<local_directory>] [--no-log] [--log-dir=<log_directory>] [--debug]
Parameters:
--apply|-a : apply SUDO controls remotely (~targets)
@ -490,23 +533,25 @@ Parameters:
--fix-remote : fix permissions on the remote SUDO controls repository
--help|-h : this help text
--local-dir : location of the SUDO control files on the local filesystem.
[default: ${LOCAL_DIR}]
[default: see LOCAL_DIR setting]
--log-dir : specify a log directory location.
--no-log : do not log any messages to the script log file.
--preview-global|-p : dump the global grant namespace (after alias resolution)
--remote-dir : directory where SUDO control files are/should be
located/copied on/to the target host
[default: ${REMOTE_DIR}]
[default: see REMOTE_DIR setting]
--slave : perform actions in master->slave mode
--targets : comma-separated list of target hosts to operate on. Override the
hosts contained in the 'targets' configuration file.
--update|-u : apply SUDO controls locally
--version|-V : show the script version/release/fix
Note 1: distribute and update actions are run in parallel across a maximum of
${MAX_BACKGROUND_PROCS} clients at the same time.
Note 1: copy and apply actions are run in parallel across a maximum of clients
at the same time [default: see MAX_BACKGROUND_PROCS setting]
Note 2: make sure correct 'sudo' rules are setup on the target systems to allow
the SUDO controls script to run with elevated privileges.
Note 2: for fix and apply actions: make sure correct 'sudo' rules are setup
on the target systems to allow the SSH controls script to run with
elevated privileges.
Note 3: only GLOBAL configuration files will be distributed to target hosts.
@ -592,6 +637,33 @@ fi
return ${ERROR_COUNT}
}
# -----------------------------------------------------------------------------
# distribute SUDO controls to a single host in slave mode
function distribute2slave
{
SERVER="$1"
# convert line to hostname
SERVER=${SERVER%%;*}
resolve_host ${SERVER}
if (( $? ))
then
warn "could not lookup host ${SERVER}, skipping"
return 1
fi
log "copying SUDO controls on ${SERVER} in slave mode, this may take a while ..."
( RC=0; ssh -A ${SSH_ARGS} ${SERVER} ${REMOTE_DIR}/${SCRIPT_NAME} --copy;
print "$?" > ${TMP_RC_FILE}; exit
) 2>&1 | logc
# fetch return code from subshell
RC="$(< ${TMP_RC_FILE})"
return ${RC}
}
# -----------------------------------------------------------------------------
function do_cleanup
{
@ -607,7 +679,7 @@ then
[[ -f ${TMP_SCAN_FILE} ]] && rm -f ${TMP_SCAN_FILE} >/dev/null 2>&1
fi
log "*** finish of ${SCRIPT_NAME} [${CMD_LINE}] ***"
log "*** finish of ${SCRIPT_NAME} [${CMD_LINE}] /$$@${HOST_NAME}/ ***"
return 0
}
@ -629,7 +701,7 @@ then
return 1
fi
log "fixing sudo controls on ${SERVER} ..."
log "fixing SUDO controls on ${SERVER} ..."
if [[ -z "${SUDO_UPDATE_USER}" ]]
then
# own user w/ sudo
@ -655,6 +727,75 @@ RC="$(< ${TMP_RC_FILE})"
return ${RC}
}
# -----------------------------------------------------------------------------
# fix SUDO controls on a single host/client in slave mode (permissions/ownerships)
# !! requires appropriate 'sudo' rules on remote client for privilege elevation
function fix2slave
{
SERVER="$1"
SERVER_DIR="$2"
# convert line to hostname
SERVER=${SERVER%%;*}
resolve_host ${SERVER}
if (( $? ))
then
warn "could not lookup host ${SERVER}, skipping"
return 1
fi
log "fixing sudo controls on ${SERVER} in slave mode, this may take a while ..."
( RC=0; ssh -A ${SSH_ARGS} ${SERVER} ${REMOTE_DIR}/${SCRIPT_NAME} --fix-remote --fix-dir=${SERVER_DIR};
print "$?" > ${TMP_RC_FILE}; exit
) 2>&1 | logc
# fetch return code from subshell
RC="$(< ${TMP_RC_FILE})"
return ${RC}
}
# -----------------------------------------------------------------------------
function get_linux_name
{
LSB_NAME="$(lsb_release -is 2>/dev/null | cut -f2 -d':')"
print "${LSB_NAME}"
return 0
}
# -----------------------------------------------------------------------------
function get_linux_version
{
LSB_VERSION="$(lsb_release -rs 2>/dev/null | cut -f1 -d'.')"
if [[ -z "${LSB_VERSION}" ]]
then
RELEASE_STRING="$(grep -i 'release' /etc/redhat-release 2>/dev/null)"
case "${RELEASE_STRING}" in
*release\ 5*)
RHEL_VERSION=5
;;
*release\ 6*)
RHEL_VERSION=6
;;
*release\ 7*)
RHEL_VERSION=7
;;
*)
RHEL_VERSION=""
;;
esac
print "${RHEL_VERSION}"
else
print "${LSB_VERSION}"
fi
return 0
}
# -----------------------------------------------------------------------------
# log an INFO: message (via ARG).
function log
@ -884,6 +1025,78 @@ cd ${OLD_PWD}
return ${SFTP_RC}
}
# -----------------------------------------------------------------------------
# start a SSH agent
function start_ssh_agent
{
log "requested to start an SSH agent on ${HOST_NAME} ..."
# is there one still running, then we re-use it
if [[ -n "${SSH_AGENT_PID}" ]]
then
log "SSH agent already running on ${HOST_NAME} with PID: ${SSH_AGENT_PID}"
else
# start the SSH agent
eval $(ssh-agent) >/dev/null 2>/dev/null
if [[ -z "${SSH_AGENT_PID}" ]]
then
warn "unable to start SSH agent on ${HOST_NAME}"
return 1
else
log "SSH agent started on ${HOST_NAME}:"
log "$(ps -fp ${SSH_AGENT_PID})"
fi
fi
# add the private key
log "adding private key ${SSH_PRIVATE_KEY} to SSH agent on ${HOST_NAME} ..."
log "$(ssh-add ${SSH_PRIVATE_KEY} 2>&1)"
if (( $? ))
then
warn "unable to add SSH private key to SSH agent on ${HOST_NAME}"
return 1
fi
return 0
}
# -----------------------------------------------------------------------------
function stop_ssh_agent
{
# stop the SSH agent
log "stopping SSH agent (if needed) on ${HOST_NAME} ..."
if [[ -n "${SSH_AGENT_PID}" ]]
then
# SIGTERM
log "stopping (TERM) process on ${HOST_NAME} with PID: ${SSH_AGENT_PID}"
log "$(ps -fp ${SSH_AGENT_PID})"
kill -s TERM ${SSH_AGENT_PID}
sleep 3
# SIGKILL
if (( $(pgrep -u "${USER}" ssh-agent | grep -c "${SSH_AGENT_PID}") ))
then
log "stopping (KILL) process on ${HOST_NAME} with PID: ${SSH_AGENT_PID}"
log "$(ps -fp ${SSH_AGENT_PID})"
kill -s kill ${SSH_AGENT_PID}
fi
sleep 3
else
log "no SSH agent running on ${HOST_NAME}"
fi
# process check
if (( $(pgrep -u "${USER}" ssh-agent | grep -c "${SSH_AGENT_PID}") ))
then
warn "unable to stop running SSH agent on ${HOST_NAME} [PID=${SSH_AGENT_PID}]"
return 1
fi
return 0
}
# -----------------------------------------------------------------------------
# update SUDO controls on a single host/client
# !! requires appropriate 'sudo' rules on remote client for privilege elevation
@ -900,7 +1113,7 @@ then
return 1
fi
log "setting sudo controls on ${SERVER} ..."
log "setting SUDO controls on ${SERVER} ..."
if [[ -z "${SUDO_UPDATE_USER}" ]]
then
# own user w/ sudo
@ -926,6 +1139,32 @@ RC="$(< ${TMP_RC_FILE})"
return ${RC}
}
# -----------------------------------------------------------------------------
# update SUDO controls on a single host/client in slave mode
function update2slave
{
SERVER="$1"
# convert line to hostname
SERVER=${SERVER%%;*}
resolve_host ${SERVER}
if (( $? ))
then
warn "could not lookup host ${SERVER}, skipping"
return 1
fi
log "applying SUDO controls on ${SERVER} in slave mode, this may take a while ..."
( RC=0; ssh -A ${SSH_ARGS} ${SERVER} ${REMOTE_DIR}/${SCRIPT_NAME} --apply;
print "$?" > ${TMP_RC_FILE}; exit
) 2>&1 | logc
# fetch return code from subshell
RC="$(< ${TMP_RC_FILE})"
return ${RC}
}
# -----------------------------------------------------------------------------
# wait for child processes to exit
function wait_for_children
@ -1076,6 +1315,13 @@ do
}
ARG_ACTION=7
;;
-m|-make-finger|--make-finger)
(( ARG_ACTION )) && {
print -u2 "ERROR: multiple actions specified"
exit 1
}
ARG_ACTION=3
;;
-fix-local|--fix-local)
(( ARG_ACTION )) && {
print -u2 "ERROR: multiple actions specified"
@ -1144,6 +1390,9 @@ do
--remote-dir=*)
ARG_REMOTE_DIR="${PARAMETER#--remote-dir=}"
;;
-slave|--slave)
DO_SLAVE=1
;;
-targets=*)
ARG_TARGETS="${PARAMETER#-targets=}"
;;
@ -1182,7 +1431,7 @@ check_params && check_config && check_setup && check_logging
# catch shell signals
trap 'do_cleanup; exit' 1 2 3 15
log "*** start of ${SCRIPT_NAME} [${CMD_LINE}] ***"
log "*** start of ${SCRIPT_NAME} [${CMD_LINE}] /$$@${HOST_NAME}/ ***"
(( ARG_LOG )) && log "logging takes places in ${LOG_FILE}"
log "runtime info: LOCAL_DIR is set to: ${LOCAL_DIR}"
@ -1191,6 +1440,23 @@ case ${ARG_ACTION} in
1) # apply SUDO controls remotely
log "ACTION: apply SUDO controls remotely"
check_root_user && die "must NOT be run as user 'root'"
# start SSH agent (if needed)
if (( DO_SSH_AGENT && CAN_START_AGENT ))
then
start_ssh_agent
if (( $? ))
then
die "problem with launching an SSH agent, bailing out"
fi
fi
if (( DO_SLAVE && DO_SSH_SLAVE_AGENT && CAN_START_AGENT ))
then
start_ssh_agent
if (( $? ))
then
die "problem with launching an SSH agent, bailing out"
fi
fi
# build clients list (in array)
cat "${TARGETS_FILE}" | grep -v -E -e '^#' -e '^$' |\
{
@ -1206,7 +1472,12 @@ case ${ARG_ACTION} in
COUNT=${MAX_BACKGROUND_PROCS}
for CLIENT in ${CLIENTS[@]}
do
if (( DO_SLAVE ))
then
update2slave ${CLIENT} &
else
update2host ${CLIENT} &
fi
PID=$!
log "updating ${CLIENT} in background [PID=${PID}] ..."
# add PID to list of all child PIDs
@ -1225,12 +1496,31 @@ case ${ARG_ACTION} in
# final wait for background processes to be finished completely
wait_for_children ${PIDS} || \
warn "$? background jobs (possibly) failed to complete correctly"
# stop SSH agent if needed
(( ( DO_SSH_AGENT || ( DO_SLAVE && DO_SSH_SLAVE_AGENT )) && CAN_START_AGENT )) && \
stop_ssh_agent
log "finished applying SUDO controls remotely"
;;
2) # copy/distribute SUDO controls
log "ACTION: copy/distribute SUDO controls"
check_root_user && die "must NOT be run as user 'root'"
# start SSH agent (if needed)
if (( DO_SSH_AGENT && CAN_START_AGENT ))
then
start_ssh_agent
if (( $? ))
then
die "problem with launching an SSH agent, bailing out"
fi
fi
if (( DO_SLAVE && DO_SSH_SLAVE_AGENT && CAN_START_AGENT ))
then
start_ssh_agent
if (( $? ))
then
die "problem with launching an SSH agent, bailing out"
fi
fi
# build clients list (in array)
cat "${TARGETS_FILE}" | grep -v -E -e '^#' -e '^$' |\
{
@ -1246,7 +1536,12 @@ case ${ARG_ACTION} in
COUNT=${MAX_BACKGROUND_PROCS}
for CLIENT in ${CLIENTS[@]}
do
if (( DO_SLAVE ))
then
distribute2slave ${CLIENT} &
else
distribute2host ${CLIENT} &
fi
PID=$!
log "copying/distributing to ${CLIENT} in background [PID=${PID}] ..."
# add PID to list of all child PIDs
@ -1265,6 +1560,9 @@ case ${ARG_ACTION} in
# final wait for background processes to be finished completely
wait_for_children ${PIDS} || \
warn "$? background jobs (possibly) failed to complete correctly"
# stop SSH agent if needed
(( ( DO_SSH_AGENT || ( DO_SLAVE && DO_SSH_SLAVE_AGENT )) && CAN_START_AGENT )) && \
stop_ssh_agent
log "finished copying/distributing SUDO controls"
;;
3) # perform syntax checking
@ -1350,8 +1648,17 @@ case ${ARG_ACTION} in
fi
if [[ -d "${FIX_DIR}/sudoers.d" ]]
then
case ${OS_NAME} in
*HP-UX*)
# sudo >v1.8
chmod 755 "${FIX_DIR}/sudoers.d" 2>/dev/null && \
chown bin:bin "${FIX_DIR}/sudoers.d" 2>/dev/null
;;
*)
chmod 755 "${FIX_DIR}/sudoers.d" 2>/dev/null && \
chown root:sys "${FIX_DIR}/sudoers.d" 2>/dev/null
;;
esac
fi
# checking files (sudoers.d/* are fixed by update_sudo.pl)
for FILE in grants alias fragments ${GLOBAL_CONFIG_FILE} update_sudo.conf
@ -1379,15 +1686,25 @@ case ${ARG_ACTION} in
# check for SELinux labels
case ${OS_NAME} in
*Linux*)
case "$(getenforce)" in
LINUX_NAME="$(get_linux_name)"
LINUX_VERSION="$(get_linux_version)"
case ${LINUX_NAME} in
*Centos*|*RHEL*)
case "$(getenforce 2>/dev/null)" in
*Permissive*|*Enforcing*)
case "${LINUX_VERSION}" in
5|6|7 )
chcon -R -t etc_t "${FIX_DIR}/sudoers.d"
;;
esac
;;
*Disabled*)
:
;;
esac
;;
esac
;;
*)
:
;;
@ -1400,6 +1717,23 @@ case ${ARG_ACTION} in
6) # fix remote directory structure/perms/ownerships
log "ACTION: fix remote SUDO controls repository"
check_root_user && die "must NOT be run as user 'root'"
# start SSH agent (if needed)
if (( DO_SSH_AGENT && CAN_START_AGENT ))
then
start_ssh_agent
if (( $? ))
then
die "problem with launching an SSH agent, bailing out"
fi
fi
if (( DO_SLAVE && DO_SSH_SLAVE_AGENT && CAN_START_AGENT ))
then
start_ssh_agent
if (( $? ))
then
die "problem with launching an SSH agent, bailing out"
fi
fi
# derive SUDO controls repo from $REMOTE_DIR:
# /etc/sudo_controls/holding -> /etc/sudo_controls
FIX_DIR="$(print ${REMOTE_DIR%/*})"
@ -1420,9 +1754,14 @@ case ${ARG_ACTION} in
COUNT=${MAX_BACKGROUND_PROCS}
for CLIENT in ${CLIENTS[@]}
do
if (( DO_SLAVE ))
then
fix2slave ${CLIENT} "${FIX_DIR}" &
else
fix2host ${CLIENT} "${FIX_DIR}" &
fi
PID=$!
log "copying/distributing to ${CLIENT} in background [PID=${PID}] ..."
log "fixing SUDO controls on ${CLIENT} in background [PID=${PID}] ..."
# add PID to list of all child PIDs
PIDS="${PIDS} ${PID}"
COUNT=$(( COUNT - 1 ))
@ -1439,6 +1778,9 @@ case ${ARG_ACTION} in
# final wait for background processes to be finished completely
wait_for_children ${PIDS} || \
warn "$? background jobs (possibly) failed to complete correctly"
# stop SSH agent if needed
(( ( DO_SSH_AGENT || ( DO_SLAVE && DO_SSH_SLAVE_AGENT )) && CAN_START_AGENT )) && \
stop_ssh_agent
log "finished applying fixes to the remote SUDO control repository"
;;
7) # dump the configuration namespace