diff --git a/manage_ssh.conf b/manage_ssh.conf index 5d70967..6de5d01 100644 --- a/manage_ssh.conf +++ b/manage_ssh.conf @@ -16,6 +16,9 @@ SSH_TRANSFER_USER="" # name of the OS group that should own the SSH controls files SSH_OWNER_GROUP="sshadmin" +# whether a 'chmod' needs to be executed after each sftp transfer [0=Yes; 1=No] +DO_SFTP_CHMOD=0 + # extra arguments/options for the SFTP command SFTP_ARGS="-o StrictHostKeyChecking=no -o ConnectTimeout=10 -b - " diff --git a/manage_ssh.sh b/manage_ssh.sh index abc1565..67fffc5 100644 --- a/manage_ssh.sh +++ b/manage_ssh.sh @@ -38,6 +38,9 @@ # @(#) 2015-08-15: 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] +# @(#) 2015-08-26: added DO_SFTP_CHMOD configuration parameter to avoid +# @(#) setstat failures with sftp_file() when remote file +# @(#) permissions do not allow (VRF 1.2.1) [Patrick Van der Veken] # ----------------------------------------------------------------------------- # DO NOT CHANGE THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING! #****************************************************************************** @@ -51,7 +54,7 @@ # or LOCAL_CONFIG_FILE instead # define the V.R.F (version/release/fix) -MY_VRF="1.2.0" +MY_VRF="1.2.1" # name of the global configuration file (script) GLOBAL_CONFIG_FILE="manage_ssh.conf" # name of the local configuration file (script) @@ -115,6 +118,12 @@ then print -u2 "ERROR: you must define a value for the REMOTE_DIR setting in $0" exit 1 fi +# DO_SFTP_CHMOD +if [[ -z "${DO_SFTP_CHMOD}" ]] +then + print -u2 "ERROR: you must define a value for the DO_SFTP_CHMOD setting in $0" + exit 1 +fi # SSH_UPDATE_USER if [[ -z "${SSH_UPDATE_USER}" ]] then @@ -685,17 +694,22 @@ TRANSFER_FILE="${TRANSFER_FILE%!*}" SOURCE_FILE="${TRANSFER_FILE##*/}" OLD_PWD=$(pwd) && cd ${TRANSFER_DIR} -# transfer, chmod the file to/on the target server (keep STDERR) -# chmod is not possible in the used security model as files should be -# owned by root, so must be disabled. This requires a fix operation right -# after the very first initial SSH controls distribution: -# ./manage_ssh.sh --fix-local --fix-dir=/etc/ssh_controls -sftp ${SFTP_ARGS} ${SSH_TRANSFER_USER}@${TRANSFER_HOST} >/dev/null </dev/null </dev/null < 'sshd_key_t', # initialize variables my ($debug, $verbose, $preview, $remove, $global, $use_fqdn) = (0,0,0,0,0,0); my (@config_files, @zombie_files, $access_dir, $blacklist_file); -my (%options, @uname, @accounts, %aliases, %keys, %access, @blacklist); +my (%options, @uname, @pwgetent, @accounts, %aliases, %keys, %access, @blacklist); my ($os, $hostname, $run_dir); my ($selinux_status, $selinux_context, $linux_version, $has_selinux) = ("","","",0); $|++; @@ -220,32 +220,15 @@ if ($options{'debug'}) { } $verbose = 1 if ($options{'verbose'}); -# what am I? -@uname = uname(); -$os = $uname[0]; -# who am I? -unless ($preview and $global) { - if ($< != 0) { - do_log ("ERROR: script must be invoked as user 'root' [$hostname]") - and exit (1); - } -} -# where am I? -unless ($use_fqdn) { - $hostname = hostfqdn(); -} else { - $hostname = hostname(); -} -$0 =~ /^(.+[\\\/])[^\\\/]+[\\\/]*$/; -my $run_dir = $1 || "."; -$run_dir =~ s#/$##; # remove trailing slash - -do_log ("INFO: runtime info: ".getpwuid ($<)."; $hostname\@${run_dir}; Perl v$]"); - # ----------------------------------------------------------------------------- # check/process configuration files, environment checks # ----------------------------------------------------------------------------- +# where am I? (1/2) +$0 =~ /^(.+[\\\/])[^\\\/]+[\\\/]*$/; +my $run_dir = $1 || "."; +$run_dir =~ s#/$##; # remove trailing slash + # don't do anything without configuration file(s) do_log ("INFO: parsing configuration file(s) ..."); push (@config_files, "$run_dir/$global_config_file") if (-f "$run_dir/$global_config_file"); @@ -287,24 +270,41 @@ unless ($preview and $global) { } } -# ----------------------------------------------------------------------------- -# collect local user accounts from /etc/passwd -# result: %accounts -# ----------------------------------------------------------------------------- - -do_log ("INFO: reading user accounts from /etc/passwd ..."); - -open (PASSWD, "/etc/passwd") - or do_log ("ERROR: cannot read PASSWD file [$! $hostname]") and exit (1); -while () { - - my @pw_entry; - - chomp (); - @pw_entry = split (/:/); - push (@accounts, $pw_entry[0]); +# what am I? +@uname = uname(); +$os = $uname[0]; +# who am I? +unless ($preview and $global) { + if ($< != 0) { + do_log ("ERROR: script must be invoked as user 'root' [$hostname]") + and exit (1); + } } -close (PASSWD); +# where am I? (2/2) +if ($use_fqdn) { + $hostname = hostfqdn(); +} else { + $hostname = hostname(); +} + +do_log ("INFO: runtime info: ".getpwuid ($<)."; ${hostname}\@${run_dir}; Perl v$]"); + +# ----------------------------------------------------------------------------- +# collect user accounts via getpwent() +# result: @accounts +# ----------------------------------------------------------------------------- + +do_log ("INFO: reading user accounts from pwgetent ..."); + +while (@pwgetent = getpwent()) { + + push (@accounts, $pwgetent[0]); +} + +# remove duplicates (which should not happen (!) but local, LDAP and accounts +# from other sources might trample over each other) +my %uniq_accounts = map { $_, 0 } @accounts; +@accounts = keys %uniq_accounts; do_log ("INFO: ".scalar (@accounts)." user accounts found on $hostname"); print Dumper (\@accounts) if $debug; @@ -339,7 +339,7 @@ print Dumper (\%aliases) if $debug; # string to resolve_aliases so don't forget to smash everything back together # first. foreach my $key (keys (%aliases)) { - + $aliases{$key} = [resolve_aliases (join (",", @{$aliases{$key}}))]; } @@ -563,7 +563,7 @@ unless ($preview) { } } -# only add authorized_keys for existing local accounts, +# only add authorized_keys for existing accounts, # otherwise revoke access if needed foreach my $account (sort (@accounts)) { @@ -701,6 +701,8 @@ Following settings must be configured: =over 2 +=item * B : whether to use short or FQDN host names + =item * B : target directory for allowed SSH public key files =item * B : location of the file with blacklisted SSH public keys @@ -771,3 +773,4 @@ S< >Show version of the script. @(#) 2014-12-16: VRF 1.0.1: added SELinux context, new config option 'selinux_context' [Patrick Van der Veken] @(#) 2015-08-08: VRF 1.0.2: small fix for 'cut' command [Patrick Van der Veken] @(#) 2015-08-15: 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.2.0: replace read of /etc/passwd by pwgetent() call, small and not so small fixes [Patrick Van der Veken] \ No newline at end of file