3457 lines
120 KiB
Bash
3457 lines
120 KiB
Bash
# -- #!/bin/bash --
|
|
# cygwin-service-installation-helper.sh
|
|
#
|
|
# Copyright (c) 2010-2015 Charles S. Wilson, Corinna Vinschen,
|
|
# Pierre Humblett, and others listed in
|
|
# AUTHORS
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person
|
|
# obtaining a copy of this software and associated documentation
|
|
# files (the "Software"), to deal in the Software without
|
|
# restriction, including without limitation the rights to use,
|
|
# copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the
|
|
# Software is furnished to do so, subject to the following
|
|
# conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be
|
|
# included in all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
# OTHER DEALINGS IN THE SOFTWARE
|
|
#
|
|
# -#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-
|
|
#
|
|
# This is a script library used to assist installing cygwin
|
|
# services, such as sshd. It is derived in part from various
|
|
# other sources (see AUTHORS).
|
|
#
|
|
# Do not attempt to run this file. Instead, it should be "sourced" by
|
|
# configuration scripts (such as a newer version of ssh-host-config,
|
|
# syslog-config, or iu-config) -- and that script should then use
|
|
# the shell functions defined here.
|
|
#
|
|
# -#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-
|
|
#
|
|
# REQUIREMENTS:
|
|
# SHELL must be bash
|
|
#
|
|
# PROVIDES:
|
|
# csih_error
|
|
# csih_error_multi
|
|
# csih_error_recoverable
|
|
# csih_warning
|
|
# csih_inform
|
|
# csih_verbose
|
|
# csih_request
|
|
# csih_get_value
|
|
# csih_get_cygenv
|
|
# csih_is_nt
|
|
# csih_is_2k
|
|
# csih_is_xp
|
|
# csih_is_nt2003
|
|
# csih_is_vista
|
|
# csih_is_windows7
|
|
# csih_is_windows8
|
|
# csih_is_windows8_1
|
|
# csih_is_windows10
|
|
# csih_is_exactly_vista
|
|
# csih_is_exactly_server2008
|
|
# csih_is_exactly_windows7
|
|
# csih_is_exactly_windows8
|
|
# csih_is_exactly_windows8_1
|
|
# csih_is_exactly_windows10
|
|
# csih_is_exactly_server2008r2
|
|
# csih_is_exactly_server2012
|
|
# csih_is_exactly_server2012r2
|
|
# csih_is_exactly_server2016
|
|
# csih_version_ge
|
|
# csih_version_le
|
|
# csih_version_gt
|
|
# csih_version_lt
|
|
# csih_version_eq
|
|
# csih_check_program
|
|
# csih_check_program_or_warn
|
|
# csih_check_program_or_error
|
|
# csih_invoke_helper
|
|
# csih_call_winsys32
|
|
# csih_get_localized_account_name
|
|
# csih_get_guest_account_name
|
|
# csih_guest_account_active
|
|
# csih_install_config
|
|
# csih_make_dir
|
|
# csih_get_system_and_admins_ids
|
|
# csih_check_passwd_and_group
|
|
# csih_old_cygwin
|
|
# csih_use_file_etc
|
|
# csih_check_user
|
|
# csih_check_dir_perms
|
|
# csih_check_access
|
|
# csih_check_sys_mount
|
|
# csih_privileged_accounts
|
|
# csih_privileged_account_exists
|
|
# csih_account_has_necessary_privileges
|
|
# csih_select_privileged_username
|
|
# csih_create_privileged_user
|
|
# csih_create_unprivileged_user
|
|
# csih_create_local_group
|
|
# csih_service_should_run_as
|
|
# csih_disable_color
|
|
# csih_enable_color
|
|
# csih_path_supports_acls
|
|
# csih_cygver
|
|
# csih_cygver_is_oneseven
|
|
# csih_cygwin_is_64bit
|
|
# csih_win_product_name
|
|
# csih_writable_tmpdir
|
|
# csih_mktemp
|
|
#
|
|
# DEBUG SUPPORT:
|
|
# csih_stacktrace
|
|
# csih_trace_on
|
|
# csih_trace_off
|
|
#
|
|
# MUTABLE VARIABLES:
|
|
# csih_sanity_check_server
|
|
# if "yes", the initial sanity check will test for tools only used when
|
|
# installing a service. As of the time of writing these are "cygrunsrv"
|
|
# and "editrights".
|
|
# This variable must be set in the calling installer script *before*
|
|
# sourcing cygwin-service-installation-helper.sh, otherwise it has no
|
|
# effect.
|
|
# csih_required_commands[]
|
|
# This variable, too, must be set in the calling installer script *before*
|
|
# sourcing cygwin-service-installation-helper.sh, otherwise it has no
|
|
# effect.
|
|
# An array which contains commands used by the calling installer script
|
|
# and the Cygwin package the command is part of. The commands are tested
|
|
# for existence at startup. If one or more commands don't exist or are
|
|
# not executable, cygwin-service-installation-helper.sh provides a helpful
|
|
# error message and refuses to run.
|
|
# The array has to be organized in pairs command/package. The commands
|
|
# *shall* be given with full path, and the installer script *shall* use
|
|
# all external commands always with full paths as well to make sure the
|
|
# required commands are not clobbered by other commands with the same
|
|
# name due to the settings of $PATH.
|
|
# Here's an example how csih_required_commands should be declared in the
|
|
# calling installer script:
|
|
# declare -a csih_required_commands[]=(
|
|
# /usr/bin/ls coreutils
|
|
# /usr/bin/passwd cygwin
|
|
# /usr/sbin/telnetd inteutils
|
|
# )
|
|
# csih_FORCE_PRIVILEGED_USER
|
|
# if "yes", then create a privileged user even on NT/2k/XP(32)
|
|
# where it is not required (on those versions, LocalSystem
|
|
# will do fine).
|
|
# Set by caller foo-config.
|
|
# NOTE: on NT/2k/XP(32), IF a well-known privileged user already
|
|
# exists and has all necessary capabilities, then it will
|
|
# be used regardless. This variable forces the creation
|
|
# and use of a privileged user, on NT/2k/XP(32), when one does
|
|
# not already exist.
|
|
# SYSCONFDIR
|
|
# default value = "/etc", or set by caller foo-config.
|
|
# LOCALSTATEDIR
|
|
# default value = "/var", or set by caller foo-config.
|
|
# csih_auto_answer
|
|
# default value = "" (no automatic answers)
|
|
# Set by caller foo-config
|
|
# csih_value
|
|
# set by csih_get_value
|
|
# foo-config should treat as read-only
|
|
# csih_cygenv
|
|
# set by csih_get_cygenv
|
|
# foo-config should treat as read-only
|
|
# csih_localized_account_name
|
|
# set by csih_get_localized_account_name, csih_get_guest_account_name
|
|
# foo-config should treat as read-only
|
|
# csih_helper_stdout
|
|
# csih_helper_stderr
|
|
# set by csih_invoke_helper and stores the stdout/stderr of the target
|
|
# program. However, if csih_invoke_helper is called in a subshell (e.g.
|
|
# myResult=$(csih_invoke_helper target arg1 arg2)
|
|
# then these values are not available to the caller outside that subshell.
|
|
# foo-config should treat as read-only
|
|
# csih_ADMINSGID
|
|
# csih_ADMINSUID
|
|
# csih_SYSTEMGID
|
|
# csih_SYSTEMUID
|
|
# these four are set by csih_get_system_and_admins_ids (called by _csih_setup)
|
|
# foo-config should treat as read-only
|
|
# csih_PRIVILEGED_USERNAME
|
|
# Set by csih_select_privileged_username (or by calling
|
|
# csih_create_privileged_user, or as a side-effect of calling
|
|
# csih_service_should_run_as) but may be set explicitly by foo-config
|
|
# foo-config should treat as read-only after first call to any csih_*
|
|
# function
|
|
# csih_PRIVILEGED_USERWINNAME
|
|
# Set by csih_select_privileged_username. While csih_PRIVILEGED_USERNAME
|
|
# is the Cygwin username, csih_PRIVILEGED_USERWINNAME is the Windows
|
|
# username. This can be used in conjunction with...
|
|
# csih_PRIVILEGED_USERDOMAIN
|
|
# Set by csih_select_privileged_username. This is the Windows domain or,
|
|
# on non-domain machines, the machine name.
|
|
# csih_PRIVILEGED_PASSWORD
|
|
# Set by csih_create_privileged_user
|
|
# foo-config treat as read-only. To "prime" the value, pass as first argument
|
|
# when calling csih_create_privileged_user
|
|
# csih_UNPRIVILEGED_USERNAME
|
|
# Set by calling csih_create_unprivileged_user.
|
|
# csih_UNPRIVILEGED_USERWINNAME
|
|
# Set by calling csih_create_unprivileged_user.
|
|
# While csih_UNPRIVILEGED_USERNAME is the Cygwin username,
|
|
# csih_UNPRIVILEGED_USERWINNAME is the Windows username. This can be
|
|
# used in conjunction with...
|
|
# csih_UNPRIVILEGED_USERDOMAIN
|
|
# Set by calling csih_create_unprivileged_user. This is the Windows
|
|
# domain or, on non-domain machines, the machine name.
|
|
# csih_LOCAL_GROUPNAME
|
|
# Set by calling csih_create_local_group.
|
|
# csih_LOCAL_GROUPWINNAME
|
|
# Set by calling csih_create_local_group.
|
|
# While csih_LOCAL_GROUPNAME is the Cygwin username,
|
|
# csih_LOCAL_GROUPWINNAME is the Windows username. This can be
|
|
# used in conjunction with...
|
|
# csih_LOCAL_GROUPDOMAIN
|
|
# Set by calling csih_create_local_group. This is the Windows
|
|
# domain or, on non-domain machines, the machine name.
|
|
# csih_WIN32_VOLS_WITH_ACLS
|
|
# a ;-separated list of windows volumes that are guaranteed to support
|
|
# ACLS, even if the getVolInfo program doesn't think so. Used to override
|
|
# getVolInfo when it is wrong (use only as a last resort; getVolInfo is
|
|
# actually faster)
|
|
# Set by caller foo-config
|
|
# csih_WIN32_VOLS_WITHOUT_ACLS=
|
|
# a ;-separated list of windows volumes that do NOT support ACLS, even if
|
|
# the getVolInfo program thinks so. Used to override getVolInfo when it
|
|
# is wrong (use only as a last resort; getVolInfo is actually faster)
|
|
# Set by caller foo-config
|
|
#
|
|
# CONST variables
|
|
# csih_VERSION
|
|
# csih_progname
|
|
# csih_progname_base
|
|
#
|
|
# ======================================================================
|
|
# Initial setup, default values, etc. PART 1
|
|
# ======================================================================
|
|
csih_progname=$0
|
|
csih_VERSION=0.9.8
|
|
readonly csih_progname csih_VERSION
|
|
|
|
csih_auto_answer=""
|
|
csih_value=
|
|
csih_cygenv=
|
|
csih_localized_account_name=
|
|
csih_FORCE_PRIVILEGED_USER=no
|
|
csih_ADMINSGID=
|
|
csih_ADMINSUID=
|
|
csih_SYSTEMGID=
|
|
csih_SYSTEMUID=
|
|
csih_PRIVILEGED_USERNAME=
|
|
csih_PRIVILEGED_USERWINNAME=
|
|
csih_PRIVILEGED_USERDOMAIN=
|
|
csih_PRIVILEGED_PASSWORD=
|
|
csih_UNPRIVILEGED_USERNAME=
|
|
csih_UNPRIVILEGED_USERWINNAME=
|
|
csih_UNPRIVILEGED_USERDOMAIN=
|
|
csih_LOCAL_GROUPNAME=
|
|
csih_LOCAL_GROUPWINNAME=
|
|
csih_LOCAL_GROUPDOMAIN=
|
|
csih_helper_stdout=
|
|
csih_helper_stderr=
|
|
csih_WIN32_VOLS_WITH_ACLS=
|
|
csih_WIN32_VOLS_WITHOUT_ACLS=
|
|
|
|
# delay initialization
|
|
_csih_exec_dir=
|
|
_csih_script_dir=
|
|
|
|
_csih_trace=
|
|
_csih_win_product_name="unknown"
|
|
|
|
if [ -z "${SYSCONFDIR}" ]
|
|
then
|
|
SYSCONFDIR=/etc
|
|
fi
|
|
|
|
if [ -z "${LOCALSTATEDIR}" ]
|
|
then
|
|
LOCALSTATEDIR=/var
|
|
fi
|
|
|
|
_csih_all_preexisting_privileged_accounts=
|
|
_csih_preferred_preexisting_privileged_account=
|
|
_csih_setup_already_called=0
|
|
_csih_writable_tmpdir_cache_value=
|
|
_csih_version_parse_pkg_major=
|
|
_csih_version_parse_pkg_minor=
|
|
_csih_version_parse_pkg_micro=
|
|
_csih_w32vol_as_shell_pattern=
|
|
_csih_w32vol_as_shell_pattern_trailing_slash=
|
|
|
|
_csih_well_known_privileged_accounts="cyg_server
|
|
sshd_server
|
|
cron_server
|
|
$COMPUTERNAME+cyg_server
|
|
$COMPUTERNAME+sshd_server
|
|
$COMPUTERNAME+cron_server"
|
|
_csih_well_known_privileged_accounts_quoted="'cyg_server'
|
|
'sshd_server'
|
|
'cron_server'
|
|
'$COMPUTERNAME+cyg_server'
|
|
'$COMPUTERNAME+sshd_server'
|
|
'$COMPUTERNAME+cron_server'"
|
|
readonly _csih_well_known_privileged_accounts _csih_well_known_privileged_accounts_quoted
|
|
|
|
_csih_ERROR_STR_COLOR="\e[1;31m*** ERROR:\e[0;0m"
|
|
_csih_WARN_STR_COLOR="\e[1;33m*** Warning:\e[0;0m"
|
|
_csih_INFO_STR_COLOR="\e[1;32m*** Info:\e[0;0m"
|
|
_csih_QUERY_STR_COLOR="\e[1;35m*** Query:\e[0;0m"
|
|
_csih_STACKTRACE_STR_COLOR="\e[1;36m*** STACKTRACE:\e[0;0m"
|
|
readonly _csih_ERROR_STR_COLOR _csih_WARN_STR_COLOR
|
|
readonly _csih_INFO_STR_COLOR _csih_QUERY_STR_COLOR _csih_STACKTRACE_STR_COLOR
|
|
|
|
_csih_ERROR_STR_PLAIN="*** ERROR:"
|
|
_csih_WARN_STR_PLAIN="*** Warning:"
|
|
_csih_INFO_STR_PLAIN="*** Info:"
|
|
_csih_QUERY_STR_PLAIN="*** Query:"
|
|
_csih_STACKTRACE_STR_PLAIN="*** STACKTRACE:"
|
|
readonly _csih_ERROR_STR_PLAIN _csih_WARN_STR_PLAIN
|
|
readonly _csih_INFO_STR_PLAIN _csih_QUERY_STR_PLAIN _csih_STACKTRACE_STR_PLAIN
|
|
|
|
_csih_ERROR_STR="${_csih_ERROR_STR_COLOR}"
|
|
_csih_WARN_STR="${_csih_WARN_STR_COLOR}"
|
|
_csih_INFO_STR="${_csih_INFO_STR_COLOR}"
|
|
_csih_QUERY_STR="${_csih_QUERY_STR_COLOR}"
|
|
_csih_STACKTRACE_STR="${_csih_STACKTRACE_STR_COLOR}"
|
|
|
|
# ======================================================================
|
|
# Routine: csih_disable_color
|
|
# Provided so that scripts which are invoked via postinstall
|
|
# can prevent escape codes from showing up in /var/log/setup.log
|
|
# ======================================================================
|
|
csih_disable_color()
|
|
{
|
|
_csih_ERROR_STR="${_csih_ERROR_STR_PLAIN}"
|
|
_csih_WARN_STR="${_csih_WARN_STR_PLAIN}"
|
|
_csih_INFO_STR="${_csih_INFO_STR_PLAIN}"
|
|
_csih_QUERY_STR="${_csih_QUERY_STR_PLAIN}"
|
|
_csih_STACKTRACE_STR="${_csih_STACKTRACE_STR_PLAIN}"
|
|
} # === End of csih_disable_color() === #
|
|
readonly -f csih_disable_color
|
|
|
|
# ======================================================================
|
|
# Routine: csih_enable_color
|
|
# ======================================================================
|
|
csih_enable_color()
|
|
{
|
|
_csih_ERROR_STR="${_csih_ERROR_STR_COLOR}"
|
|
_csih_WARN_STR="${_csih_WARN_STR_COLOR}"
|
|
_csih_INFO_STR="${_csih_INFO_STR_COLOR}"
|
|
_csih_QUERY_STR="${_csih_QUERY_STR_COLOR}"
|
|
_csih_STACKTRACE_STR="${_csih_STACKTRACE_STR_COLOR}"
|
|
} # === End of csih_enable_color() === #
|
|
readonly -f csih_enable_color
|
|
|
|
# ======================================================================
|
|
# Routine: csih_stacktrace
|
|
# ======================================================================
|
|
csih_stacktrace()
|
|
{
|
|
set +x # don''t trace this!
|
|
local -i n=$(( ${#FUNCNAME} - 1 ))
|
|
local val=""
|
|
if [ -n "$_csih_trace" ]
|
|
then
|
|
while [ $n -gt 0 ]
|
|
do
|
|
if [ -n "${FUNCNAME[$n]}" ]
|
|
then
|
|
if [ -z "$val" ]
|
|
then
|
|
val="${FUNCNAME[$n]}[${BASH_LINENO[$(($n-1))]}]"
|
|
else
|
|
val="${val}->${FUNCNAME[$n]}[${BASH_LINENO[$(($n-1))]}]"
|
|
fi
|
|
fi
|
|
n=$(($n-1))
|
|
done
|
|
echo -e "${_csih_STACKTRACE_STR} ${val} ${@}" 1>&2
|
|
fi
|
|
} # === End of csih_stacktrace() === #
|
|
readonly -f csih_stacktrace
|
|
|
|
# ======================================================================
|
|
# Routine: csih_trace_on
|
|
# turns on shell tracing of csih functions
|
|
# ======================================================================
|
|
csih_trace_on()
|
|
{
|
|
_csih_trace='set -x'
|
|
trap 'csih_stacktrace "returning with" $?; set -x' RETURN
|
|
set -T
|
|
csih_stacktrace "${@}"
|
|
} # === End of csih_trace_on() === #
|
|
readonly -f csih_trace_on
|
|
|
|
# ======================================================================
|
|
# Routine: csih_trace_off
|
|
# turns off shell tracing of csih functions
|
|
# ======================================================================
|
|
csih_trace_off()
|
|
{
|
|
trap '' RETURN
|
|
csih_stacktrace "${@}"
|
|
_csih_trace=
|
|
set +x
|
|
set +T
|
|
} # === End of csih_trace_off() === #
|
|
readonly -f csih_trace_off
|
|
|
|
# ======================================================================
|
|
# Routine: csih_error
|
|
# Prints the (optional) error message $1, then
|
|
# Exits with the error code contained in $? if $? is non-zero, otherwise
|
|
# exits with status 1
|
|
# All other arguments are ignored
|
|
# Example: csih_error "missing file"
|
|
# NEVER RETURNS
|
|
# ======================================================================
|
|
csih_error()
|
|
{
|
|
local errorcode=$?
|
|
set +x # don't trace this, but we are interested in who called
|
|
csih_stacktrace # we'll see the arguments in the next statement
|
|
if ((errorcode == 0))
|
|
then
|
|
errorcode=1
|
|
fi
|
|
echo -e "${_csih_ERROR_STR} ${1:-no error message provided}"
|
|
exit ${errorcode};
|
|
} # === End of csih_error() === #
|
|
readonly -f csih_error
|
|
|
|
# ======================================================================
|
|
# Routine: csih_error_multi
|
|
# Prints the (optional) error messages in the positional arguments, one
|
|
# per line, and then
|
|
# Exits with the error code contained in $? if $? is non-zero, otherwise
|
|
# exits with status 1
|
|
# All other arguments are ignored
|
|
# Example: csih_error_multi "missing file" "see documentation"
|
|
# NEVER RETURNS
|
|
# ======================================================================
|
|
csih_error_multi()
|
|
{
|
|
local errorcode=$?
|
|
set +x # don't trace this, but we are interested in who called
|
|
csih_stacktrace # we'll see the arguments in the next statement
|
|
if ((errorcode == 0))
|
|
then
|
|
errorcode=1
|
|
fi
|
|
while test $# -gt 1
|
|
do
|
|
echo -e "${_csih_ERROR_STR} ${1}"
|
|
shift
|
|
done
|
|
echo -e "${_csih_ERROR_STR} ${1:-no error message provided}"
|
|
exit ${errorcode};
|
|
} # === End of csih_error_multi() === #
|
|
readonly -f csih_error_multi
|
|
|
|
# ======================================================================
|
|
# Routine: csih_error_recoverable
|
|
# Prints the supplied errormessage, and propagates the $? value
|
|
# Example: csih_error_recoverable "an error message"
|
|
# ======================================================================
|
|
csih_error_recoverable()
|
|
{
|
|
local errorcode=$?
|
|
set +x # don't trace this, but we are interested in who called
|
|
csih_stacktrace # we'll see the arguments in the next statement
|
|
echo -e "${_csih_ERROR_STR} ${1}"
|
|
$_csih_trace
|
|
return $errorcode
|
|
} # === End of csih_error_recoverable() === #
|
|
readonly -f csih_error_recoverable
|
|
|
|
|
|
# ======================================================================
|
|
# Routine: csih_warning
|
|
# Prints the supplied warning message
|
|
# Example: csih_warning "replacing default file foo"
|
|
# ======================================================================
|
|
csih_warning()
|
|
{
|
|
set +x # don't trace this, but we are interested in who called
|
|
csih_stacktrace # we'll see the arguments in the next statement
|
|
echo -e "${_csih_WARN_STR} ${1}"
|
|
$_csih_trace
|
|
} # === End of csih_warning() === #
|
|
readonly -f csih_warning
|
|
|
|
# ======================================================================
|
|
# Routine: csih_inform
|
|
# Prints the supplied informational message
|
|
# Example: csih_inform "beginning dependency analysis..."
|
|
# ======================================================================
|
|
csih_inform()
|
|
{
|
|
set +x # don't trace this, but we are interested in who called
|
|
csih_stacktrace # we'll see the arguments in the next statement
|
|
echo -e "${_csih_INFO_STR} ${1}"
|
|
$_csih_trace
|
|
} # === End of csih_inform() === #
|
|
readonly -f csih_inform
|
|
|
|
# ======================================================================
|
|
# Routine: csih_verbose
|
|
# prints the supplied command line
|
|
# executes it
|
|
# returns the error status of the command
|
|
# Example: csih_verbose /usr/bin/rm -f /etc/config-file
|
|
# ======================================================================
|
|
csih_verbose()
|
|
{
|
|
set +x # don't trace this, but we are interested in who called
|
|
local rstatus
|
|
csih_stacktrace # we'll see the arguments in the next statement
|
|
echo "${@}" 1>&2
|
|
"${@}"
|
|
rstatus=$?
|
|
$_csih_trace
|
|
return $rstatus
|
|
} # === End of csih_verbose() === #
|
|
readonly -f csih_verbose
|
|
|
|
# ======================================================================
|
|
# Routine: csih_check_program
|
|
# Check to see that the specified program(s) ($1, $2, ...) are installed
|
|
# and executable by this script. Returns as soon as it encounters a
|
|
# missing or non-executable program. Returns 1 if it can't find the
|
|
# program, 2 if it's not executable.
|
|
# ======================================================================
|
|
csih_check_program()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local prog
|
|
local fullpath
|
|
|
|
for prog
|
|
do
|
|
# To maintain backward compatibility, check if hash can find programs
|
|
# which are not given with full path.
|
|
if ! [[ "${prog}" =~ ^/ ]]
|
|
then
|
|
hash "${prog}" 2>/dev/null || return 1
|
|
prog="$(hash -t "${prog}")"
|
|
fi
|
|
test -e ${prog} || return 1
|
|
test -x ${prog} || return 2
|
|
done
|
|
|
|
return 0;
|
|
} # === End of csih_check_program() === #
|
|
readonly -f csih_check_program
|
|
|
|
# ======================================================================
|
|
# Routine: csih_check_program_or_warn
|
|
# Check to see that a specified program ($1) is installed and executable
|
|
# by this script. If not, warn the user that a particular package
|
|
# ($2) is required and return non-zero (false)
|
|
# Otherwise, return 0 (true)
|
|
# ======================================================================
|
|
csih_check_program_or_warn()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local prog=${1};
|
|
local pkg=${2:-${1}};
|
|
|
|
csih_check_program "${prog}"
|
|
case $? in
|
|
0)
|
|
return 0
|
|
;;
|
|
1)
|
|
csih_warning "Cannot find required command $prog."
|
|
;;
|
|
2)
|
|
csih_warning "Cannot execute required program $prog."
|
|
;;
|
|
esac
|
|
csih_warning "Please (re)install the ${pkg} package.";
|
|
return 1;
|
|
} # === End of csih_check_program_or_warn() === #
|
|
readonly -f csih_check_program_or_warn
|
|
|
|
# ======================================================================
|
|
# Routine: csih_check_program_or_error
|
|
# Check to see that a specified program ($1) is installed and executable
|
|
# by this script. If not, inform the user that a particular package
|
|
# ($2) is required, and exit with error
|
|
# ======================================================================
|
|
csih_check_program_or_error()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local prog=${1};
|
|
local pkg=${2:-${1}};
|
|
|
|
csih_check_program "${prog}"
|
|
case $? in
|
|
0)
|
|
return 0
|
|
;;
|
|
1)
|
|
csih_error_recoverable "Cannot find required command $prog."
|
|
;;
|
|
2)
|
|
csih_error_recoverable "Cannot execute required program $prog."
|
|
;;
|
|
esac
|
|
csih_error "Please (re)install the ${pkg} package.";
|
|
return 1;
|
|
} # === End of csih_check_program_or_error() === #
|
|
readonly -f csih_check_program_or_error
|
|
|
|
# ======================================================================
|
|
# Routine: _csih_sanity_check
|
|
# Check for the set of programs that are used by this script.
|
|
# Exits on failure
|
|
# ======================================================================
|
|
_csih_sanity_check()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local ret=0
|
|
# Check for programs that this script uses.
|
|
local -a cmd=(
|
|
/usr/bin/awk gawk
|
|
/usr/bin/basename coreutils
|
|
/usr/bin/chmod coreutils
|
|
/usr/bin/cat coreutils
|
|
/usr/bin/chown coreutils
|
|
/usr/bin/cp coreutils
|
|
/usr/bin/cut coreutils
|
|
/usr/bin/cygpath cygwin
|
|
/usr/bin/dirname coreutils
|
|
/usr/bin/expr coreutils
|
|
/usr/bin/getent getent
|
|
/usr/bin/getfacl cygwin
|
|
/usr/bin/grep grep
|
|
/usr/bin/id coreutils
|
|
/usr/bin/ls coreutils
|
|
/usr/bin/mkdir coreutils
|
|
/usr/bin/mkgroup cygwin
|
|
/usr/bin/mkpasswd cygwin
|
|
/usr/bin/mktemp coreutils
|
|
/usr/bin/mount cygwin
|
|
/usr/bin/mv cygwin
|
|
/usr/bin/rm coreutils
|
|
/usr/bin/sed sed
|
|
/usr/bin/setfacl cygwin
|
|
/usr/bin/stat coreutils
|
|
/usr/bin/tr coreutils
|
|
/usr/bin/uname coreutils
|
|
# do not check for editrights and cygrunsrv here -- clients which use this
|
|
# library may not need their functionality. See below for the function
|
|
# csih_sanity_check_server which can be called by the main script to test
|
|
# for these commands.
|
|
)
|
|
for (( i=0; i < ${#cmd[*]}; i+=2 ))
|
|
do
|
|
csih_check_program_or_warn "${cmd[i]}" "${cmd[i+1]}" || ret=1
|
|
done
|
|
if [ "${csih_sanity_check_server}" = "yes" \
|
|
-o "${csih_sanity_check_server}" = "1" ]
|
|
then
|
|
csih_check_program_or_warn /usr/bin/cygrunsrv cygrunsrv || ret=1
|
|
csih_check_program_or_warn /usr/bin/editrights editrights || ret=1
|
|
fi
|
|
# The calling script may add commands which should be checked.
|
|
# It can do so by defining an array called 'csih_required_commands'.
|
|
# It must consist of pairs command/package, just like the above 'cmd' array.
|
|
for (( i=0; i < ${#csih_required_commands[*]}; i+=2 ))
|
|
do
|
|
if ! [[ "${cmd[@]}" =~ "${csih_required_commands[i]}" ]]
|
|
then
|
|
csih_check_program_or_warn "${csih_required_commands[i]}" "${csih_required_commands[i+1]}" || ret=1
|
|
fi
|
|
done
|
|
if [ $ret -ne 0 ]
|
|
then
|
|
csih_error_multi \
|
|
"There is something badly wrong with your cygwin installation." \
|
|
"" \
|
|
"Please install the missing command(s), and make sure all required" \
|
|
"command are executable. Otherwise the installation provided by this" \
|
|
"script will fail." \
|
|
"" \
|
|
"To fix this problem, run {rh}setup.exe and (re)install the" \
|
|
"packages mentioned in the warnings above."
|
|
fi
|
|
} # === End of _csih_sanity_check() === #
|
|
readonly -f _csih_sanity_check
|
|
|
|
# ======================================================================
|
|
# DEPRECATED: csih_sanity_check
|
|
# Stub for backward compatibility
|
|
# ======================================================================
|
|
function csih_sanity_check()
|
|
{
|
|
csih_warning "$csih_progname_base is using deprecated "\
|
|
"function csih_sanity_check. Continuing..."
|
|
true
|
|
} # === End of csih_sanity_check() === #
|
|
readonly -f csih_sanity_check
|
|
|
|
# ======================================================================
|
|
# Initial setup, default values, etc. PART 2
|
|
#
|
|
# This part of the setup has to be deferred since first we have to make
|
|
# sure that all required tools are available. This makes for a bit of
|
|
# mess as far as the order of function definitions goes, but since the
|
|
# file is sourced, we have to make sure that certain tests are running
|
|
# first, especially the test for missing commands used by this script.
|
|
#
|
|
# Consequentially the call to _csih_sanity_check is done first.
|
|
# ======================================================================
|
|
_csih_sanity_check
|
|
|
|
csih_progname_base=$(/usr/bin/basename -- $csih_progname)
|
|
readonly csih_progname_base
|
|
_csih_sys="$(/usr/bin/uname)"
|
|
_csih_xp=0
|
|
_csih_nt2003=0
|
|
_csih_vista=0
|
|
_csih_windows7=0
|
|
_csih_windows8=0
|
|
_csih_windows8_1=0
|
|
_csih_windows10=0
|
|
_csih_exactly_server2008=0
|
|
_csih_exactly_server2008r2=0
|
|
_csih_exactly_server2012=0
|
|
_csih_exactly_vista=0
|
|
_csih_exactly_windows7=0
|
|
_csih_exactly_windows8=0
|
|
_csih_exactly_windows8_1=0
|
|
_csih_exactly_windows10=0
|
|
# If running on NT, check if running under XP(64), 2003 Server, or later
|
|
_csih_xp=$(/usr/bin/uname | /usr/bin/awk -F- '{print ( $2 >= 5.1 ) ? 1 : 0;}')
|
|
_csih_nt2003=$(/usr/bin/uname | /usr/bin/awk -F- '{print ( $2 >= 5.2 ) ? 1 : 0;}') # also true for XP(64)
|
|
_csih_vista=$(/usr/bin/uname | /usr/bin/awk -F- '{print ( $2 >= 6.0 ) ? 1 : 0;}')
|
|
_csih_windows7=$(/usr/bin/uname | /usr/bin/awk -F- '{print ( $2 >= 6.1 ) ? 1 : 0;}')
|
|
_csih_windows8=$(/usr/bin/uname | /usr/bin/awk -F- '{print ( $2 >= 6.2 ) ? 1 : 0;}')
|
|
_csih_windows8_1=$(/usr/bin/uname | /usr/bin/awk -F- '{print ( $2 >= 6.3 ) ? 1 : 0;}')
|
|
_csih_windows10=$(/usr/bin/uname | /usr/bin/awk -F- '{print ( $2 >= 6.4 ) ? 1 : 0;}')
|
|
readonly _csih_sys _csih_xp _csih_nt2003 _csih_vista _csih_windows7 _csih_windows8 _csih_windows8_1 _csih_windows10
|
|
_csih_cygver=$(b=$(/usr/bin/uname -r) && echo "${b%%(*}")
|
|
_csih_cygver_is_oneseven=$(echo ${_csih_cygver} | /usr/bin/awk -F. '{print ( $1 > 1 || ($1 == 1 && $2 >= 7) ) ? 1 : 0;}')
|
|
_csih_cygwin_is_64bit=$(/usr/bin/uname -m | grep 'x86_64' >/dev/null && echo 1 || echo 0)
|
|
readonly _csih_cygver _csih_cygver_is_oneseven _csih_cygwin_is_64bit
|
|
|
|
# ======================================================================
|
|
# Routine: csih_is_nt
|
|
# returns 0 (true)
|
|
# ======================================================================
|
|
csih_is_nt()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
return 0
|
|
} # === End of csih_is_nt() === #
|
|
readonly -f csih_is_nt
|
|
# ======================================================================
|
|
# Routine: csih_is_2k
|
|
# returns 0 (true)
|
|
# ======================================================================
|
|
csih_is_2k()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
return 0
|
|
} # === End of csih_is_2k() === #
|
|
readonly -f csih_is_2k
|
|
# ======================================================================
|
|
# Routine: csih_is_xp
|
|
# returns 0 (true)
|
|
# ======================================================================
|
|
csih_is_xp()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
return 0
|
|
} # === End of csih_is_xp() === #
|
|
readonly -f csih_is_xp
|
|
# ======================================================================
|
|
# Routine: csih_is_nt2003
|
|
# returns 0 (true) if the system is Windows XP 64bit, or Windows
|
|
# Server 2003 or above.
|
|
# returns 1 (false) otherwise
|
|
#
|
|
# Note that this routine is somewhat misnamed, since it returns true for
|
|
# 64bit Windows XP, but not 32bit Windows XP, as well as the nominal
|
|
# "NT Server 2003 and above" operating systems. This is because 64bit XP
|
|
# was developed by Microsoft after the release of the 32bit version, and
|
|
# unlike the older 32bit XP, the 64bit XP uses the same kernel as the
|
|
# (then also under development) Windows Server 2003. The key point is
|
|
# that all Windows operating systems with kernel >= 5.2 (e.g. 64bit
|
|
# Windows XP, Windows NT Server 2003, and above) share the same
|
|
# restriction with regards to the capabilities of the SYSTEM
|
|
# (LocalSystem) account: on those platforms, SYSTEM cannot change the
|
|
# effective user. This is a key capability for services, and many
|
|
# 'foo-config' clients use csih_is_nt2003 to check whether a special
|
|
# "privileged" user must be created, as do several csih_* functions
|
|
# such as csih_select_privileged_username().
|
|
# ======================================================================
|
|
csih_is_nt2003()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_nt2003} -gt 0
|
|
} # === End of csih_is_nt2003() === #
|
|
readonly -f csih_is_nt2003
|
|
# ======================================================================
|
|
# Routine: csih_is_vista
|
|
# returns 0 (true) if the system is Windows Vista/Windows Server 2008
|
|
# or above.
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_is_vista()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_vista} -gt 0
|
|
} # === End of csih_is_vista() === #
|
|
readonly -f csih_is_vista
|
|
# ======================================================================
|
|
# Routine: csih_is_windows7
|
|
# returns 0 (true) if the system is Windows 7/Windows Server 2008r2
|
|
# or above.
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_is_windows7()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_windows7} -gt 0
|
|
} # === End of csih_is_windows7() === #
|
|
readonly -f csih_is_windows7
|
|
# ======================================================================
|
|
# Routine: csih_is_windows8
|
|
# returns 0 (true) if the system is Windows 8/Windows 8 Server
|
|
# or above.
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_is_windows8()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_windows8} -gt 0
|
|
} # === End of csih_is_windows8() === #
|
|
readonly -f csih_is_windows8
|
|
# ======================================================================
|
|
# Routine: csih_is_windows8_1
|
|
# returns 0 (true) if the system is Windows 8.1/Windows 8.1 Server
|
|
# or above.
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_is_windows8_1()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_windows8_1} -gt 0
|
|
} # === End of csih_is_windows8_1() === #
|
|
readonly -f csih_is_windows8_1
|
|
# ======================================================================
|
|
# Routine: csih_is_windows10
|
|
# returns 0 (true) if the system is Windows 10/Windows 10 Server
|
|
# or above.
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_is_windows10()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_windows10} -gt 0
|
|
} # === End of csih_is_windows10() === #
|
|
readonly -f csih_is_windows10
|
|
# ======================================================================
|
|
# Routine: csih_cygver
|
|
# returns the dotted-triple version number of the currently-running
|
|
# cygwin dll. Avoids forking uname multiple times.
|
|
# ======================================================================
|
|
csih_cygver()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
echo $_csih_cygver
|
|
} # === End of csih_cygver() === #
|
|
readonly -f csih_cygver
|
|
# ======================================================================
|
|
# Routine: csih_cygver_is_oneseven
|
|
# returns 0 (true) if the currently-running cygwin dll is version
|
|
# 1.7.0 or above (including pre-release betas).
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_cygver_is_oneseven()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
return 0
|
|
} # === End of csih_cygver_is_oneseven() === #
|
|
readonly -f csih_cygver_is_oneseven
|
|
# ======================================================================
|
|
# Routine: csih_cygwin_is_64bit
|
|
# returns 0 (true) if the currently-running cygwin dll is 64bit
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_cygwin_is_64bit()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_cygwin_is_64bit} -gt 0
|
|
} # === End of csih_cygwin_is_64bit() === #
|
|
readonly -f csih_cygwin_is_64bit
|
|
# ======================================================================
|
|
# Routine: csih_is_exactly_vista
|
|
# returns 0 (true) if the system is one of the variants of
|
|
# Windows Vista (Home Basic, Home Premium, Business, etc) but NOT
|
|
# Server2008 or some newer edition (like Windows7)
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_is_exactly_vista()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_exactly_vista} -gt 0
|
|
} # === End of csih_is_exactly_vista() === #
|
|
#NOTE: do not make _csih_exactly_vista readonly YET
|
|
|
|
# ======================================================================
|
|
# Routine: csih_is_exactly_server2008
|
|
# returns 0 (true) if the system is one of the variants of
|
|
# Windows Server 2008 but NOT one of the variants of Vista, nor
|
|
# some newer edition (like Windows7)
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_is_exactly_server2008()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_exactly_server2008} -gt 0
|
|
} # === End of csih_is_exactly_server2008() === #
|
|
#NOTE: do not make _csih_exactly_server2008 readonly YET
|
|
|
|
# ======================================================================
|
|
# Routine: csih_is_exactly_windows7
|
|
# returns 0 (true) if the system is one of the variants of
|
|
# Windows 7 (Home Premium, Professional, etc) but NOT Server2008R2
|
|
# or some newer edition like Windows 8.
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_is_exactly_windows7()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_exactly_windows7} -gt 0
|
|
} # === End of csih_is_exactly_windows7() === #
|
|
#NOTE: do not make _csih_exactly_windows7 readonly YET
|
|
|
|
# ======================================================================
|
|
# Routine: csih_is_exactly_server2008r2
|
|
# returns 0 (true) if the system is one of the variants of
|
|
# Windows Server 2008 R2 but NOT one of the variants of Windows7,
|
|
# nor some newer edition.
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_is_exactly_server2008r2()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_exactly_server2008r2} -gt 0
|
|
} # === End of csih_is_exactly_server2008r2() === #
|
|
#NOTE: do not make _csih_exactly_server2008r2 readonly YET
|
|
|
|
# ======================================================================
|
|
# Routine: csih_is_exactly_windows8
|
|
# returns 0 (true) if the system is one of the variants of
|
|
# Windows 8 (Home Premium, Professional, etc) but NOT
|
|
# Windows 8 Server or some newer edition.
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_is_exactly_windows8()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_exactly_windows8} -gt 0
|
|
} # === End of csih_is_exactly_windows8() === #
|
|
#NOTE: do not make _csih_exactly_windows8 readonly YET
|
|
|
|
# ======================================================================
|
|
# Routine: csih_is_exactly_server2012
|
|
# returns 0 (true) if the system is one of the variants of
|
|
# Windows 2012 Server but NOT one of the variants of Windows 8,
|
|
# nor some newer edition.
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_is_exactly_server2012()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_exactly_server2012} -gt 0
|
|
} # === End of csih_is_exactly_server2012() === #
|
|
#NOTE: do not make _csih_exactly_server2012 readonly YET
|
|
|
|
# ======================================================================
|
|
# Routine: csih_is_exactly_windows8_1
|
|
# returns 0 (true) if the system is one of the variants of
|
|
# Windows 8.1 (Home Premium, Professional, etc) but NOT
|
|
# Windows 8.1 Server or some newer edition.
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_is_exactly_windows8_1()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
e test ${_csih_exactly_windows8_1} -gt 0
|
|
} # === End of csih_is_exactly_windows8_1() === #
|
|
#NOTE: do not make _csih_exactly_windows8_1 readonly YET
|
|
|
|
# ======================================================================
|
|
# Routine: csih_is_exactly_server2012r2
|
|
# returns 0 (true) if the system is one of the variants of
|
|
# Windows 2012 Server but NOT one of the variants of Windows 8,
|
|
# nor some newer edition.
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_is_exactly_server2012r2()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_exactly_server2012r2} -gt 0
|
|
} # === End of csih_is_exactly_server2012r2() === #
|
|
#NOTE: do not make _csih_exactly_server2012r2 readonly YET
|
|
|
|
# ======================================================================
|
|
# Routine: csih_is_exactly_windows10
|
|
# returns 0 (true) if the system is one of the variants of
|
|
# Windows 8 (Home Premium, Professional, etc) but NOT
|
|
# Windows 8 Server or some newer edition.
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_is_exactly_windows10()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_exactly_windows10} -gt 0
|
|
} # === End of csih_is_exactly_windows10() === #
|
|
#NOTE: do not make _csih_exactly_windows10 readonly YET
|
|
|
|
# ======================================================================
|
|
# Routine: csih_is_exactly_server2016
|
|
# returns 0 (true) if the system is one of the variants of
|
|
# Windows 2016 Server.
|
|
# returns 1 (false) otherwise
|
|
# ======================================================================
|
|
csih_is_exactly_server2016()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
test ${_csih_exactly_server2016} -gt 0
|
|
} # === End of csih_is_exactly_server2016() === #
|
|
#NOTE: do not make _csih_exactly_server2016 readonly YET
|
|
|
|
# ======================================================================
|
|
# Routine: csih_win_product_name
|
|
# Allows to cache the result of calling winProductName.
|
|
# ======================================================================
|
|
csih_win_product_name()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
echo $_csih_win_product_name
|
|
} # === End of csih_win_product_name() === #
|
|
#NOTE: do not make _csih_win_product_name readonly YET
|
|
|
|
# ======================================================================
|
|
# Routine: csih_writable_tmpdir
|
|
# Echos to stdout the name of a writable temporary directory, based
|
|
# on the values of $TMP, $TEMP, $TMPDIR, or $HOME, with a fallback to
|
|
# /tmp. As a last resort, attempts to create /tmp.
|
|
#
|
|
# Returns 0 on success, nonzero on error.
|
|
# ======================================================================
|
|
csih_writable_tmpdir()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local tdir
|
|
|
|
if [ -z "${_csih_writable_tmpdir_cache_value}" ]
|
|
then
|
|
if [ -n "${TMP}" -a -d "${TMP}" -a -w "${TMP}" ]
|
|
then
|
|
tdir="${TMP}"
|
|
elif [ -n "${TEMP}" -a -d "${TEMP}" -a -w "${TEMP}" ]
|
|
then
|
|
tdir="${TEMP}"
|
|
elif [ -n "${TMPDIR}" -a -d "${TMPDIR}" -a -w "${TMPDIR}" ]
|
|
then
|
|
tdir="${TMPDIR}"
|
|
elif [ -d "/tmp" -a -w "/tmp" ]
|
|
then
|
|
tdir="/tmp"
|
|
elif [ -n "${HOME}" -a -d "${HOME}" -a -w "${HOME}" ]
|
|
then
|
|
tdir="${HOME}"
|
|
else
|
|
# fall back to creating /tmp manually
|
|
/usr/bin/mkdir -p -m 1777 /tmp
|
|
if [ $? -eq 0 ]
|
|
then
|
|
tdir="/tmp"
|
|
else
|
|
csih_warning "Cannot find or create a writable temporary directory"
|
|
return 1
|
|
fi
|
|
fi
|
|
_csih_writable_tmpdir_cache_value="${tdir}"
|
|
fi
|
|
echo "${_csih_writable_tmpdir_cache_value}"
|
|
} # === End of csih_writable_tmpdir() === #
|
|
readonly -f csih_writable_tmpdir
|
|
|
|
# ======================================================================
|
|
# Routine: csih_mktemp
|
|
# Safe wrapper around mktemp. Should be called in a subshell in order
|
|
# to capture the name of the created file: tmpfile="$(csih_mktemp)"
|
|
# By default, mktemp is invoked with
|
|
# --tmpfile="$(csih_writable_tmpdir)"
|
|
# but that may be overridden by explictly specifying a different
|
|
# --tmpdir value.
|
|
#
|
|
# Return value is 0 on success, nonzero otherwise.
|
|
# ======================================================================
|
|
csih_mktemp ()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
|
|
local __umask=$(umask)
|
|
local rval
|
|
local tmpdir
|
|
|
|
tmpdir=$(csih_writable_tmpdir) || return 1
|
|
|
|
umask 0077
|
|
/usr/bin/mktemp --tmpdir="${tmpdir}" "$@"
|
|
rval=$?
|
|
umask ${__umask}
|
|
|
|
return $rval
|
|
} # === End of csih_mktemp() === #
|
|
readonly -f csih_mktemp
|
|
|
|
# ======================================================================
|
|
# Routine: csih_version_parse
|
|
# safely parses a version string of the form x.y.z into three
|
|
# separate values.
|
|
# ======================================================================
|
|
csih_version_parse() {
|
|
local pkg_version="$1"
|
|
|
|
# remove any non-digit characters from the version numbers to permit numeric
|
|
_csih_version_parse_pkg_major=$(echo $pkg_version | /usr/bin/cut -d. -f1 | /usr/bin/sed s/[a-zA-Z\-].*//g)
|
|
_csih_version_parse_pkg_minor=$(echo $pkg_version | /usr/bin/cut -d. -f2 | /usr/bin/sed s/[a-zA-Z\-].*//g)
|
|
_csih_version_parse_pkg_micro=$(echo $pkg_version | /usr/bin/cut -d. -f3 | /usr/bin/sed s/[a-zA-Z\-].*//g)
|
|
test -z "$_csih_version_parse_pkg_major" && _csih_version_parse_pkg_major=0
|
|
test -z "$_csih_version_parse_pkg_minor" && _csih_version_parse_pkg_minor=0
|
|
test -z "$_csih_version_parse_pkg_micro" && _csih_version_parse_pkg_micro=0
|
|
} # === End of csih_version_parse() === #
|
|
readonly -f csih_version_parse
|
|
|
|
# ======================================================================
|
|
# Routine: csih_version_ge
|
|
# Compares two version strings: $1 ad $2 should both be version
|
|
# strings of the form x.y.z
|
|
# returns true if $1 >= $2, when compared as normal version strings
|
|
# returns false otherwise
|
|
# Intended use: if client script requires csih of vintage x.y.z or above,
|
|
# if ! csih_version_ge $csih_VERSION x.y.z ; then some error ; fi
|
|
# ======================================================================
|
|
csih_version_ge() {
|
|
local lh_pkg_version="$1"
|
|
local rh_pkg_version="$2"
|
|
local lh_pkg_major
|
|
local lh_pkg_minor
|
|
local lh_pkg_micro
|
|
local rh_pkg_major
|
|
local rh_pkg_minor
|
|
local rh_pkg_micro
|
|
|
|
csih_version_parse "$lh_pkg_version"
|
|
lh_pkg_major=$_csih_version_parse_pkg_major
|
|
lh_pkg_minor=$_csih_version_parse_pkg_minor
|
|
lh_pkg_micro=$_csih_version_parse_pkg_micro
|
|
|
|
csih_version_parse "$rh_pkg_version"
|
|
rh_pkg_major=$_csih_version_parse_pkg_major
|
|
rh_pkg_minor=$_csih_version_parse_pkg_minor
|
|
rh_pkg_micro=$_csih_version_parse_pkg_micro
|
|
|
|
if [ $lh_pkg_major -gt $rh_pkg_major ]
|
|
then
|
|
return 0
|
|
elif [ $lh_pkg_major -eq $rh_pkg_major ]
|
|
then
|
|
if [ $lh_pkg_minor -gt $rh_pkg_minor ]
|
|
then
|
|
return 0
|
|
elif [ $lh_pkg_minor -eq $rh_pkg_minor ]
|
|
then
|
|
if [ $lh_pkg_micro -ge $rh_pkg_micro ]
|
|
then
|
|
return 0
|
|
fi
|
|
fi
|
|
fi
|
|
return 1
|
|
} # === End of csih_version_ge() === #
|
|
readonly -f csih_version_ge
|
|
|
|
# ======================================================================
|
|
# Routine: csih_version_le
|
|
# Compares two version strings: $1 ad $2 should both be version
|
|
# strings of the form x.y.z
|
|
# returns true if $1 <= $2, when compared as normal version strings
|
|
# returns false otherwise
|
|
# Intended use: if new versions of csih (above x.y.z) break a client script,
|
|
# it can warn the user:
|
|
# if ! csih_version_le $csih_VERSION x.y.z ; then some warning ; fi
|
|
# (However, rather than adding a warning about an incompatibility, it
|
|
# would probably be better to fix the script, or csih...)
|
|
# ======================================================================
|
|
csih_version_le() {
|
|
local lh_pkg_version="$1"
|
|
local rh_pkg_version="$2"
|
|
local lh_pkg_major
|
|
local lh_pkg_minor
|
|
local lh_pkg_micro
|
|
local rh_pkg_major
|
|
local rh_pkg_minor
|
|
local rh_pkg_micro
|
|
|
|
csih_version_parse "$lh_pkg_version"
|
|
lh_pkg_major=$_csih_version_parse_pkg_major
|
|
lh_pkg_minor=$_csih_version_parse_pkg_minor
|
|
lh_pkg_micro=$_csih_version_parse_pkg_micro
|
|
|
|
csih_version_parse "$rh_pkg_version"
|
|
rh_pkg_major=$_csih_version_parse_pkg_major
|
|
rh_pkg_minor=$_csih_version_parse_pkg_minor
|
|
rh_pkg_micro=$_csih_version_parse_pkg_micro
|
|
|
|
if [ $lh_pkg_major -lt $rh_pkg_major ]
|
|
then
|
|
return 0
|
|
elif [ $lh_pkg_major -eq $rh_pkg_major ]
|
|
then
|
|
if [ $lh_pkg_minor -lt $rh_pkg_minor ]
|
|
then
|
|
return 0
|
|
elif [ $lh_pkg_minor -eq $rh_pkg_minor ]
|
|
then
|
|
if [ $lh_pkg_micro -le $rh_pkg_micro ]
|
|
then
|
|
return 0
|
|
fi
|
|
fi
|
|
fi
|
|
return 1
|
|
} # === End of csih_version_le() === #
|
|
readonly -f csih_version_le
|
|
|
|
# ======================================================================
|
|
# Routine: csih_version_lt
|
|
# Compares two version strings: $1 ad $2 should both be version
|
|
# strings of the form x.y.z
|
|
# returns true if $1 < $2, when compared as normal version strings
|
|
# ======================================================================
|
|
csih_version_lt() {
|
|
if csih_version_ge "$1" "$2"
|
|
then
|
|
return 1
|
|
fi
|
|
return 0
|
|
} # === End of csih_version_lt() === #
|
|
readonly -f csih_version_lt
|
|
# ======================================================================
|
|
# Routine: csih_version_gt
|
|
# Compares two version strings: $1 ad $2 should both be version
|
|
# strings of the form x.y.z
|
|
# returns true if $1 > $2, when compared as normal version strings
|
|
# ======================================================================
|
|
csih_version_gt() {
|
|
if csih_version_le "$1" "$2"
|
|
then
|
|
return 1
|
|
fi
|
|
return 0
|
|
} # === End of csih_version_gt() === #
|
|
readonly -f csih_version_gt
|
|
# ======================================================================
|
|
# Routine: csih_version_eq
|
|
# Compares two version strings: $1 ad $2 should both be version
|
|
# strings of the form x.y.z
|
|
# returns true if $1 == $2, when compared as normal version strings
|
|
# ======================================================================
|
|
csih_version_eq() {
|
|
local lh_pkg_version="$1"
|
|
local rh_pkg_version="$2"
|
|
local lh_pkg_major
|
|
local lh_pkg_minor
|
|
local lh_pkg_micro
|
|
local rh_pkg_major
|
|
local rh_pkg_minor
|
|
local rh_pkg_micro
|
|
|
|
csih_version_parse "$lh_pkg_version"
|
|
lh_pkg_major=$_csih_version_parse_pkg_major
|
|
lh_pkg_minor=$_csih_version_parse_pkg_minor
|
|
lh_pkg_micro=$_csih_version_parse_pkg_micro
|
|
|
|
csih_version_parse "$rh_pkg_version"
|
|
rh_pkg_major=$_csih_version_parse_pkg_major
|
|
rh_pkg_minor=$_csih_version_parse_pkg_minor
|
|
rh_pkg_micro=$_csih_version_parse_pkg_micro
|
|
|
|
if [ $lh_pkg_major -eq $rh_pkg_major -a $lh_pkg_minor -eq $rh_pkg_minor -a $lh_pkg_micro -eq $rh_pkg_micro ]
|
|
then
|
|
return 0
|
|
fi
|
|
return 1
|
|
} # === End of csih_version_eq() === #
|
|
readonly -f csih_version_eq
|
|
|
|
# ======================================================================
|
|
# Routine: _csih_warning_for_etc_file
|
|
# Display a warning message for the user about overwriting the
|
|
# specified file in /etc.
|
|
# ======================================================================
|
|
_csih_warning_for_etc_file()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
csih_warning "The command above overwrites any existing /etc/$1."
|
|
csih_warning "You may want to preserve /etc/$1 before generating"
|
|
csih_warning "a new one, and then compare your saved /etc/$1 file"
|
|
csih_warning "with the newly-generated one in case you need to restore"
|
|
csih_warning "other entries."
|
|
} # === End of _csih_warning_for_etc_file() === #
|
|
readonly -f _csih_warning_for_etc_file
|
|
|
|
# ======================================================================
|
|
# Routine: csih_request
|
|
# Retrieve user response to a question (in the optional argument $1)
|
|
# Accepts only "yes" or "no", repeats until valid response
|
|
# If csih_auto_answer=="yes", acts as though user entered "yes"
|
|
# If csih_auto_answer=="no", acts as though user entered "no"
|
|
# If "yes" then return 0 (true)
|
|
# If "no" then return 1 (false)
|
|
# ======================================================================
|
|
csih_request()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
local answer=""
|
|
|
|
if [ "${csih_auto_answer}" = "yes" ]
|
|
then
|
|
echo -e "${_csih_QUERY_STR} $1 (yes/no) yes"
|
|
return 0
|
|
elif [ "${csih_auto_answer}" = "no" ]
|
|
then
|
|
echo -e "${_csih_QUERY_STR} $1 (yes/no) no"
|
|
return 1
|
|
fi
|
|
|
|
while true
|
|
do
|
|
echo -n -e "${_csih_QUERY_STR} $1 (yes/no) "
|
|
if read -e answer
|
|
then
|
|
if [ "X${answer}" = "Xyes" ]
|
|
then
|
|
return 0
|
|
fi
|
|
if [ "X${answer}" = "Xno" ]
|
|
then
|
|
return 1
|
|
fi
|
|
else
|
|
# user did a ^D
|
|
echo -e "Quitting.\n"
|
|
exit 1
|
|
fi
|
|
done
|
|
} # === End of csih_request() === #
|
|
readonly -f csih_request
|
|
|
|
# ======================================================================
|
|
# Routine: csih_get_value
|
|
# Get a verified non-empty string in variable "csih_value"
|
|
# Prompt with the first argument.
|
|
# The 2nd argument if not empty must be -s. (for "silent" password
|
|
# entry)
|
|
# NO AUTOANSWER SUPPORT.
|
|
# SETS GLOBAL VARIABLE: csih_value
|
|
# ======================================================================
|
|
csih_get_value()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
local value
|
|
local verify
|
|
while true
|
|
do
|
|
echo -n -e "${_csih_QUERY_STR} "
|
|
if read $2 -p "$1 " value
|
|
then
|
|
[ -n "$2" ] && echo
|
|
if [ -n "${value}" ]
|
|
then
|
|
echo -n -e "${_csih_QUERY_STR} "
|
|
read $2 -p "Reenter: " verify
|
|
[ -n "$2" ] && echo
|
|
[ "${verify}" = "${value}" ] && break
|
|
fi
|
|
else
|
|
# user did a ^D
|
|
echo -e "Quitting.\n"
|
|
exit 1
|
|
fi
|
|
done
|
|
echo
|
|
csih_value="${value}"
|
|
return 0
|
|
} # === End of csih_get_value() === #
|
|
readonly -f csih_get_value
|
|
|
|
# ======================================================================
|
|
# Routine: csih_get_cygenv
|
|
# Retrieves from user the appropriate value for the CYGWIN environment
|
|
# variable to be used with the installed service.
|
|
# All arguments are interpreted together as the desired default value
|
|
# for CYGWIN.
|
|
#
|
|
# csih_auto_answer behavior:
|
|
# if set (to either "yes" or "no"), use default value
|
|
#
|
|
# SETS GLOBAL VARIABLE: csih_cygenv
|
|
# ======================================================================
|
|
csih_get_cygenv()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local default=$*
|
|
|
|
# if there is any auto_answer setting, then accept default
|
|
if [ -n "${csih_auto_answer}" ]
|
|
then
|
|
echo -e "${_csih_QUERY_STR} Enter the value of CYGWIN for the daemon: [${default}] ${default}"
|
|
csih_cygenv="${default}"
|
|
return 0
|
|
fi
|
|
|
|
while true
|
|
do
|
|
echo -n -e "${_csih_QUERY_STR} Enter the value of CYGWIN for the daemon: [${default}] "
|
|
if read csih_cygenv
|
|
then
|
|
if [ -z "${csih_cygenv}" ]
|
|
then
|
|
csih_cygenv="${default}"
|
|
fi
|
|
return
|
|
else
|
|
# user did a ^D
|
|
echo -e "Quitting.\n"
|
|
exit 1
|
|
fi
|
|
done
|
|
} # === End of csih_get_cygenv() === #
|
|
readonly -f csih_get_cygenv
|
|
|
|
# ======================================================================
|
|
# Routine: _csih_get_script_dir
|
|
# private routine to initialize _csih_script_dir
|
|
# ======================================================================
|
|
_csih_get_script_dir() {
|
|
# should be /usr/share/csih
|
|
local d=$(/usr/bin/dirname -- ${BASH_SOURCE[0]})
|
|
local D=$(cd "$d" && pwd)
|
|
echo "$D"
|
|
} # === End of csih_get_script_dir() === #
|
|
readonly -f _csih_get_script_dir
|
|
|
|
# ======================================================================
|
|
# Routine: _csih_get_exec_dir
|
|
# private routine to initialize _csih_exec_dir
|
|
# ======================================================================
|
|
_csih_get_exec_dir() {
|
|
# should be /usr/lib/csih
|
|
local d=$(/usr/bin/dirname -- ${BASH_SOURCE[0]})
|
|
local b=$(/usr/bin/basename -- "$d")
|
|
local D=$(cd "$d/../../lib/$b" >/dev/null 2>&1 && pwd)
|
|
local fullpath=
|
|
if [ -z "$D" ]
|
|
then
|
|
# try /usr/lib/csih explicitly
|
|
if [ -f "/usr/lib/csih/getAccountName.exe" ]
|
|
then
|
|
D=/usr/lib/csih
|
|
else
|
|
# try $PATH
|
|
if hash getAccountName 2>/dev/null
|
|
then
|
|
hash ${prog} 2>/dev/null
|
|
fullpath=$(hash -t getAccountName 2>/dev/null)
|
|
D=$(/usr/bin/dirname -- "$fullpath")
|
|
else
|
|
csih_error_recoverable "Could not locate csih helper programs!"
|
|
fi
|
|
fi
|
|
fi
|
|
echo "$D"
|
|
} # === End of csih_get_exec_dir() === #
|
|
readonly -f _csih_get_exec_dir
|
|
|
|
# ======================================================================
|
|
# Routine: csih_invoke_helper
|
|
# Launches a helper program shipped with cish
|
|
# returns the exit code of the helper program
|
|
# output:
|
|
# stores stdout in 'csih_helper_stdout', and copies to real stdout
|
|
# stores stderr in 'csih_helper_stderr', and emits as a recoverable
|
|
# error to the real stderr
|
|
# Note that if csih_invoke_helper is executed in a subshell, then
|
|
# the contents of csih_helper_stdout/csih_helper_stderr are not
|
|
# available to the caller.
|
|
#
|
|
# SETS GLOBAL VARIABLE: csih_helper_stdout csih_helper_stderr
|
|
# ======================================================================
|
|
csih_invoke_helper()
|
|
{
|
|
set +x # don''t trace this, but we are interested in who called
|
|
local result
|
|
local stdout
|
|
local var_out
|
|
local var_err
|
|
local SEP="----- separator -----"
|
|
local helper=
|
|
csih_stacktrace "${@}"
|
|
helper="$1"
|
|
shift
|
|
csih_helper_stdout=""
|
|
csih_helper_stderr=""
|
|
|
|
if [ -n "${_csih_exec_dir}" ]
|
|
then
|
|
if [ -f "${_csih_exec_dir}/${helper}" ]
|
|
then
|
|
result=$( { stdout=$("${_csih_exec_dir}/${helper}" "${@}"); } 2>&1; \
|
|
printf "%s\n%d\n%s\n" "${SEP}" $? "${SEP}"; printf "%s" "$stdout" )
|
|
var_out=${result##*${SEP}$'\n'}
|
|
var_err=${result%%$'\n'${SEP}*}
|
|
var_out=${var_out/*${SEP}/}
|
|
var_err=${var_err/${SEP}*/}
|
|
result=${result%$'\n'${SEP}*}
|
|
result=${result#*${SEP}$'\n'}
|
|
if [ -n "${var_err}" ]; then
|
|
csih_helper_stderr=$(echo "$var_err" | /usr/bin/sed -e 's/\r//g')
|
|
csih_error_recoverable "${helper}: ${csih_helper_stderr//\\/\\\\}" 1>&2
|
|
fi
|
|
if [ -n "${var_out}" ]; then
|
|
csih_helper_stdout=$(echo "$var_out" | /usr/bin/sed -e 's/\r//g')
|
|
echo "${csih_helper_stdout}"
|
|
fi
|
|
else
|
|
csih_error "Could not find ${helper} in ${_csih_exec_dir}"
|
|
fi
|
|
else
|
|
csih_error "Could not find csih helper programs!"
|
|
fi
|
|
|
|
$_csih_trace
|
|
return $result
|
|
} # === End of csih_invoke_helper() === #
|
|
readonly -f csih_invoke_helper
|
|
|
|
# ======================================================================
|
|
# Routine: csih_call_winsys32
|
|
# Calls a Windows CLI tool ($1) from the /Windows/System32
|
|
# directory. The trick here is that we use a full path to call
|
|
# the tool to avoid clobbering by other commands with the same name
|
|
# earlier in $PATH. In addition, to avoid a problem where different
|
|
# versions of Windows spell the 'system32' directory with different
|
|
# capitalization, AND because we are not sure if the ${SYSTEMROOT}
|
|
# volume is case-sensitive, we exploit a loophole in cygwin's case-
|
|
# sensitive support. When a command is invoked via a full, DOS-style
|
|
# path, case-insensitive path traversal is used. Note that
|
|
# 'cygpath -m' is used rather than 'cygpath -d' to avoid the
|
|
# "MS-DOS style path detected" warning.
|
|
# ======================================================================
|
|
csih_call_winsys32()
|
|
{
|
|
local tool=$1
|
|
shift
|
|
"$(/usr/bin/cygpath -ma "${SYSTEMROOT}")/system32/${tool}" "$@"
|
|
return $?
|
|
}
|
|
readonly -f csih_call_winsys32
|
|
|
|
# ======================================================================
|
|
# Routine: csih_get_localized_account_name
|
|
# Obtains the localized account name for the specified well-known
|
|
# account, where $1 indicates by number which account is of interest.
|
|
# The account name is stored in the variable csih_localized_account_name
|
|
# See WELL_KNOWN_SID_TYPE documentation for the association between
|
|
# well known accounts and the $1 numbers accepted here. Of interest:
|
|
# Local Guest: 39
|
|
# Domain Guest: 43
|
|
# Administrator: 38
|
|
# Returns 0 on success, non-zero on failure
|
|
#
|
|
# SETS GLOBAL VARIABLE: csih_localized_account_name
|
|
# ======================================================================
|
|
csih_get_localized_account_name()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local rstatus
|
|
local name
|
|
|
|
name=$(csih_invoke_helper getAccountName --number $1)
|
|
rstatus=$?
|
|
if [ "$rstatus" -eq 0 ]
|
|
then
|
|
csih_localized_account_name="${name}"
|
|
else
|
|
csih_localized_account_name=""
|
|
fi
|
|
return $rstatus
|
|
} # === End of csih_get_localized_account_name() === #
|
|
readonly -f csih_get_localized_account_name
|
|
|
|
# ======================================================================
|
|
# Routine: csih_get_guest_account_name
|
|
# Obtains the localized account name for the Guest user.
|
|
# The account name is stored in the variable csih_localized_account_name
|
|
# Returns 0 on success, non-zero on failure
|
|
#
|
|
# SETS GLOBAL VARIABLE: csih_localized_account_name
|
|
# ======================================================================
|
|
csih_get_guest_account_name()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local name
|
|
local rstatus
|
|
|
|
name=$(csih_invoke_helper getAccountName -g)
|
|
rstatus=$?
|
|
if [ "$rstatus" -eq 0 ]
|
|
then
|
|
csih_localized_account_name="${name}"
|
|
else
|
|
csih_localized_account_name=""
|
|
fi
|
|
return $rstatus
|
|
} # === End of csih_get_guest_account_name() === #
|
|
readonly -f csih_get_guest_account_name
|
|
|
|
# ======================================================================
|
|
# Routine: _csih_convert_w32vol_to_shell_pattern
|
|
# Converts the path specified as $1 to a shell pattern suitable
|
|
# for use in a case statement. For instance:
|
|
# E: -> [Ee]:
|
|
# //server/share -> [\\/][\\/]server[\\/]share
|
|
# $1 must be in win32 format
|
|
#
|
|
# SETS GLOBAL VARIABLES:
|
|
# _csih_w32vol_as_shell_pattern
|
|
# _csih_w32vol_as_shell_pattern_trailing_slash
|
|
# ======================================================================
|
|
_csih_convert_w32vol_to_shell_pattern()
|
|
{
|
|
csih_stacktrace "${@}" 1>&2 # redirect to avoid clobbering stdout
|
|
$_csih_trace
|
|
local has_trailing_slash
|
|
local upperD
|
|
local lowerD
|
|
local w32vol="$1"
|
|
|
|
# determine if ends in '/'
|
|
case "${w32vol}" in
|
|
*/ ) has_trailing_slash=yes
|
|
w32vol="${w32vol%%/*}"
|
|
;;
|
|
esac
|
|
# replace all '/' with '[\\/]'
|
|
w32vol="${w32vol//\//[\\\\\/]}"
|
|
# replace leading 'X:' with '[Xx]:'
|
|
if [ "${w32vol:1:1}" = ":" ]
|
|
then
|
|
case "${w32vol:0:1}" in
|
|
[A-Za-z] )
|
|
lowerD=$(echo "${w32vol:0:1}" | /usr/bin/tr '[:upper:]' '[:lower:]')
|
|
upperD=$(echo "${w32vol:0:1}" | /usr/bin/tr '[:lower:]' '[:upper:]')
|
|
w32vol="[${upperD}${lowerD}]:${w32vol:2}"
|
|
;;
|
|
esac
|
|
fi
|
|
_csih_w32vol_as_shell_pattern="${w32vol}"
|
|
_csih_w32vol_as_shell_pattern_trailing_slash="${has_trailing_slash}"
|
|
} # === End of _csih_convert_w32vol_to_shell_pattern() === #
|
|
readonly -f _csih_convert_w32vol_to_shell_pattern
|
|
|
|
# ======================================================================
|
|
# Routine: _csih_path_in_volumelist_core
|
|
# Given:
|
|
# $1 == a path in win32 format
|
|
# $2 == a win32-format pathlist (;-separated)
|
|
# Prints 'found' on stdout if
|
|
# $1 is located on one of the volumes specified in $2
|
|
# Silent otherwise
|
|
#
|
|
# Implementation note: matches are executed in a subshell, so
|
|
# we can't use variables to communicate the results. This is why
|
|
# stdout is used, and why stacktrace is redirected.
|
|
# ======================================================================
|
|
_csih_path_in_volumelist_core()
|
|
{
|
|
csih_stacktrace "${@}" 1>&2 # redirect to avoid clobbering stdout
|
|
$_csih_trace
|
|
local w32path="$1"
|
|
local volumelist="$2"
|
|
|
|
echo "$volumelist" | /usr/bin/tr ';' '\n' | while read p
|
|
do
|
|
_csih_convert_w32vol_to_shell_pattern "$p"
|
|
case "$w32path" in
|
|
${_csih_w32vol_as_shell_pattern}* )
|
|
printf "found\n"
|
|
;;
|
|
${_csih_w32vol_as_shell_pattern}[\\\\/]* )
|
|
if [ -n "${_csih_w32vol_as_shell_pattern_trailing_slash}" ]
|
|
then
|
|
printf "found\n"
|
|
fi
|
|
;;
|
|
esac
|
|
done
|
|
} # === End of _csih_path_in_volumelist_core() === #
|
|
readonly -f _csih_path_in_volumelist_core
|
|
|
|
# ======================================================================
|
|
# Routine: _csih_path_in_volumelist
|
|
# Given:
|
|
# $1 == a path in win32 format
|
|
# $2 == a win32-format pathlist (;-separated)
|
|
# Returns 0 if $1 is in $2
|
|
# Returns 1 otherwise
|
|
#
|
|
# Implementation note; a simple wrapper around *_core(), to hide
|
|
# the use of stdout.
|
|
# ======================================================================
|
|
_csih_path_in_volumelist()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local result=$(_csih_path_in_volumelist_core "$1" "$2")
|
|
if [ "x${result}" = "xfound" ]
|
|
then
|
|
return 0
|
|
fi
|
|
return 1
|
|
} # === End of _csih_path_in_volumelist() === #
|
|
readonly -f _csih_path_in_volumelist
|
|
|
|
# ======================================================================
|
|
# Routine: csih_path_supports_acls
|
|
# Determines if the specified path is on a volume that supports
|
|
# persistent ACLs. This is used to skip access-permission checks
|
|
# if files are located on a volume that does not support them.
|
|
# Returns 0 on success (yes, path is on a volume that supports ACLs),
|
|
# non-zero on failure (no, it doesn't, or there was some problem making
|
|
# the determination)
|
|
#
|
|
# $1 may be in unix or win32 format
|
|
#
|
|
# NOTE:
|
|
# first checks to see if $1, after conversion to win32 format,
|
|
# is located on one of the volumes listed in the win32-format
|
|
# pathlist csih_WIN32_VOLS_WITH_ACLS. If so, returns true (0).
|
|
# NOTE: the elements of csih_WIN32_VOLS_WITH_ACLS need not
|
|
# exist, although specifying non-existent shares will cause
|
|
# execution delays.
|
|
# then checks to see if $1, after conversion to win32 format,
|
|
# is located on one of the volumes listed in the win32-format
|
|
# pathlist csih_WIN32_VOLS_WITHOUT_ACLS. If so, returns false (1).
|
|
# NOTE: the elements of csih_WIN32_VOLS_WITHOUT_ACLS need not
|
|
# exist, although specifying non-existent shares will cause
|
|
# execution delays.
|
|
# finally, runs the helper program getVolInfo for $1. If the result
|
|
# contains 'FILE_PERSISTENT_ACLS: TRUE', then returns true (0)
|
|
# otherwise, returns false (1)
|
|
# NOTE: this test will return false if $1 specifies a volume that
|
|
# does not exist.
|
|
# ======================================================================
|
|
csih_path_supports_acls()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local output
|
|
local rstatus
|
|
if [ -z "$1" ]
|
|
then
|
|
csih_warning "Internal: csih_path_supports_acls called with no argument"
|
|
return 1
|
|
fi
|
|
|
|
# convert to w32 format
|
|
w32path=$(/usr/bin/cygpath -m "$1")
|
|
|
|
if _csih_path_in_volumelist "$w32path" "$csih_WIN32_VOLS_WITH_ACLS"
|
|
then
|
|
return 0
|
|
fi
|
|
|
|
if _csih_path_in_volumelist "$w32path" "$csih_WIN32_VOLS_WITHOUT_ACLS"
|
|
then
|
|
return 1
|
|
fi
|
|
|
|
output=$(csih_invoke_helper getVolInfo "$1" | /usr/bin/grep "FILE_PERSISTENT_ACLS" 2>/dev/null)
|
|
rstatus=$?
|
|
if [ "$rstatus" -eq 0 ]
|
|
then
|
|
echo "$output" | /usr/bin/grep "TRUE" || rstatus=2
|
|
fi
|
|
return $rstatus
|
|
} # === End of csih_path_supports_acls() === #
|
|
readonly -f csih_path_supports_acls
|
|
|
|
# ======================================================================
|
|
# Routine: csih_guest_account_active
|
|
# Returns true (0) if the Guest account is active
|
|
# Returns false (non-zero) otherwise.
|
|
#
|
|
# SETS GLOBAL VARIABLE: csih_localized_account_name
|
|
# ======================================================================
|
|
csih_guest_account_active() {
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local rstatus=1
|
|
local str
|
|
|
|
if csih_get_guest_account_name
|
|
then
|
|
str=$(csih_call_winsys32 net user "$csih_localized_account_name" |\
|
|
/usr/bin/sed -n -e '/^Account active/s/^Account active *//p' |\
|
|
/usr/bin/tr '[:upper:]' '[:lower:]')
|
|
if [ "$str" = "yes" ]
|
|
then
|
|
rstatus=0
|
|
return $rstatus
|
|
fi
|
|
fi
|
|
return $rstatus
|
|
} # === End of csih_guest_account_active() === #
|
|
readonly -f csih_guest_account_active
|
|
|
|
# ======================================================================
|
|
# Routine: csih_install_config
|
|
# Installs the specified file ($1) by copying the default file
|
|
# located in the defaults directory ($2). Asks before overwriting.
|
|
# ${2}/${1} must exist. All directory components on ${1} must exist.
|
|
# Returns 0 on success, non-zero on failure
|
|
# ======================================================================
|
|
csih_install_config()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local dest;
|
|
local DEFAULTSDIR;
|
|
|
|
if [ -z "$1" ]
|
|
then
|
|
return
|
|
fi
|
|
if [ -z "$2" ]
|
|
then
|
|
return
|
|
fi
|
|
|
|
dest=$1;
|
|
DEFAULTSDIR=$2
|
|
|
|
if [ -f "$dest" ]
|
|
then
|
|
if ! csih_request "Overwrite existing ${dest} file?"
|
|
then
|
|
return 0
|
|
fi
|
|
/usr/bin/rm -f "${dest}"
|
|
if [ -f "${dest}" ]
|
|
then
|
|
csih_warning "Can't overwrite. ${dest} is write protected."
|
|
fi
|
|
fi
|
|
|
|
|
|
if [ ! -f "${dest}" ]
|
|
then
|
|
if [ ! -f "${DEFAULTSDIR}/${dest}" ]
|
|
then
|
|
csih_warning "Can't create ${dest} because default version could not be found."
|
|
csih_warning "Check '${DEFAULTSDIR}'"
|
|
else
|
|
csih_inform "Creating default ${dest} file"
|
|
/usr/bin/cp ${DEFAULTSDIR}/${dest} ${dest}
|
|
return $?
|
|
fi
|
|
fi
|
|
return 1
|
|
} # === End of csih_install_config() === #
|
|
readonly -f csih_install_config
|
|
|
|
# ======================================================================
|
|
# Routine: csih_make_dir
|
|
# Creates the specified directory if it does not already exist.
|
|
# Exits on failure.
|
|
# ======================================================================
|
|
csih_make_dir()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local DIR;
|
|
if [ -z "$1" ]
|
|
then
|
|
return
|
|
fi
|
|
DIR=$1
|
|
shift
|
|
|
|
if [ -e "${DIR}" -a ! -d "${DIR}" ]
|
|
then
|
|
if [ -n "$1" ]
|
|
then
|
|
csih_error_multi "${DIR} exists, but is not a directory." "$1"
|
|
else
|
|
csih_error "${DIR} exists, but is not a directory."
|
|
fi
|
|
fi
|
|
|
|
if [ ! -e "${DIR}" ]
|
|
then
|
|
/usr/bin/mkdir -p "${DIR}"
|
|
if [ ! -e "${DIR}" ]
|
|
then
|
|
csih_error "Creating ${DIR} directory failed."
|
|
fi
|
|
fi
|
|
} # === End of csih_make_dir() === #
|
|
readonly -f csih_make_dir
|
|
|
|
# ======================================================================
|
|
# Routine: csih_get_system_and_admins_ids
|
|
# Get the ADMINs ids from user and group account databases
|
|
# Returns 0 (true) on success, 1 otherwise.
|
|
# SETS GLOBAL VARIABLES:
|
|
# csih_ADMINSGID
|
|
# csih_ADMINSUID
|
|
# csih_SYSTEMGID
|
|
# csih_SYSTEMUID
|
|
# ======================================================================
|
|
csih_get_system_and_admins_ids()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local ret=0
|
|
|
|
# require Administrators group and SYSTEM
|
|
csih_ADMINSGID="$(/usr/bin/getent -w group S-1-5-32-544)"
|
|
csih_ADMINSGID="${csih_ADMINSGID#*:}"
|
|
csih_ADMINSGID="${csih_ADMINSGID%%:*}"
|
|
csih_SYSTEMGID="$(/usr/bin/getent -w group S-1-5-18)"
|
|
csih_SYSTEMGID="${csih_SYSTEMGID#*:}"
|
|
csih_SYSTEMGID="${csih_SYSTEMGID%%:*}"
|
|
if [ -z "$csih_ADMINSGID" -o -z "$csih_SYSTEMGID" ]
|
|
then
|
|
csih_warning "It appears that you do not have entries for the local"
|
|
csih_warning "ADMINISTRATORS and/or SYSTEM sids in /etc/group."
|
|
csih_warning ""
|
|
csih_warning "Use the 'mkgroup' utility to generate them or allow \"db\""
|
|
csih_warning "search of group accounts in /etc/nsswitch.conf"
|
|
csih_warning ""
|
|
ret=1;
|
|
fi
|
|
|
|
# only require SYSTEM passwd entry; warn if either is missing
|
|
csih_ADMINSUID="$(/usr/bin/getent -w passwd S-1-5-32-544)"
|
|
csih_ADMINSUID="${csih_ADMINSUID#*:}"
|
|
csih_ADMINSUID="${csih_ADMINSUID%%:*}"
|
|
csih_SYSTEMUID="$(/usr/bin/getent -w passwd S-1-5-18)"
|
|
csih_SYSTEMUID="${csih_SYSTEMUID#*:}"
|
|
csih_SYSTEMUID="${csih_SYSTEMUID%%:*}"
|
|
if [ -z "$csih_ADMINSUID" -o -z "$csih_SYSTEMUID" ]
|
|
then
|
|
csih_warning "It appears that you do not have an entry for the local"
|
|
csih_warning "ADMINISTRATORS (group) and/or SYSTEM sids."
|
|
csih_warning ""
|
|
csih_warning "Use the 'mkpasswd' utility to generate it or allow \"db\""
|
|
csih_warning "search of passwd accounts in /etc/nsswitch.conf"
|
|
csih_warning ""
|
|
if [ -z "$csih_SYSTEMUID" ]
|
|
then
|
|
ret=1
|
|
fi
|
|
fi
|
|
return "${ret}"
|
|
} # === End of csih_get_system_and_admins_ids() === #
|
|
readonly -f csih_get_system_and_admins_ids
|
|
|
|
# ======================================================================
|
|
# Routine: csih_check_passwd_and_group
|
|
# Check to see whether the user's password ID and group exist in the
|
|
# system account databases, respectively.
|
|
# Returns 0 (true) on success, 1 otherwise.
|
|
# ======================================================================
|
|
csih_check_passwd_and_group()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local ret=0
|
|
# Check for mkpasswd/mkgroup only valid up to Cygwin 1.7.33
|
|
if csih_old_cygwin
|
|
then
|
|
if [ "$(/usr/bin/id -un)" = "mkpasswd" ]
|
|
then
|
|
csih_warning "It appears that you do not have an entry for your user ID"
|
|
csih_warning "in /etc/passwd."
|
|
csih_warning ""
|
|
csih_warning "If so, use the 'mkpasswd' utility to generate an"
|
|
csih_warning "entry for your User ID in the password file:"
|
|
csih_warning " mkpasswd -l -u User_ID >> /etc/passwd"
|
|
csih_warning "or"
|
|
csih_warning " mkpasswd -d -u User_ID >> /etc/passwd."
|
|
csih_warning ""
|
|
_csih_warning_for_etc_file passwd
|
|
ret=1
|
|
fi
|
|
if [ "$(/usr/bin/id -gn)" = mkgroup ]
|
|
then
|
|
csih_warning "It appears that you do not have an entry for your group ID"
|
|
csih_warning "in /etc/group. If this check is incorrect, then re-run"
|
|
csih_warning "this script with the '-f' command-line option."
|
|
csih_warning ""
|
|
csih_warning "Otherwise, use the 'mkgroup' utility to generate an"
|
|
csih_warning "entry for your group ID in the password file:"
|
|
csih_warning " mkgroup -l -g Group_id >> /etc/group"
|
|
csih_warning "or"
|
|
csih_warning " mkgroup -d -g Group_id >> /etc/group."
|
|
csih_warning ""
|
|
_csih_warning_for_etc_file group
|
|
ret=1
|
|
fi
|
|
else
|
|
if ! getent passwd $(/usr/bin/id -un) >/dev/null 2>&1
|
|
then
|
|
csih_warning "It appears that you do not have an entry for your user ID"
|
|
csih_warning "in the user account database."
|
|
csih_warning ""
|
|
csih_warning "Please check the settings in /etc/nsswitch.conf."
|
|
ret=1
|
|
fi
|
|
if ! getent group $(/usr/bin/id -gn) >/dev/null 2>&1
|
|
then
|
|
csih_warning "It appears that you do not have an entry for your user ID"
|
|
csih_warning "in the group account database."
|
|
csih_warning ""
|
|
csih_warning "Please check the settings in /etc/nsswitch.conf."
|
|
ret=1
|
|
fi
|
|
fi
|
|
return "${ret}"
|
|
} # === End of csih_check_passwd_and_group() === #
|
|
readonly -f csih_check_passwd_and_group
|
|
|
|
|
|
# ======================================================================
|
|
# Routine: csih_check_user
|
|
# Check to see that the specified user exists in the user account database
|
|
# Returns 0 (true) if so, 1 otherwise.
|
|
# ======================================================================
|
|
csih_check_user()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
if ! /usr/bin/getent passwd "$1" >/dev/null 2>&1
|
|
then
|
|
csih_warning "User $1 does not appear in the user account database."
|
|
return 1;
|
|
fi
|
|
return 0
|
|
} # === End of csih_check_user() === #
|
|
readonly -f csih_check_user
|
|
|
|
# ======================================================================
|
|
# Routine: _csih_warning_for_missing_ACL_support
|
|
# Display a warning message for the user about files located on
|
|
# volumes that do not support persistent ACLS -- e.g. FAT drives,
|
|
# noacl, etc.
|
|
# ======================================================================
|
|
_csih_warning_for_missing_ACL_support()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
csih_warning "$1 exists on a volume that does not support accurate"
|
|
csih_warning "permissions (perhaps formatted FAT?). Therefore, we"
|
|
csih_warning "cannot verify access to the file or directory."
|
|
csih_warning "Please consider, if possible and appropriate, one of the"
|
|
csih_warning "following remedies:"
|
|
csih_warning " 1) converting to NTFS using 'convert.exe'"
|
|
csih_warning " 2) mounting the relevant volume using the 'acl' option"
|
|
}
|
|
# === End of _csih_warning_for_missing_ACL_support() === #
|
|
readonly -f _csih_warning_for_missing_ACL_support
|
|
|
|
# ======================================================================
|
|
# Routine: csih_check_dir_perms
|
|
# Check to see that the specified directory ($1) exists and has the
|
|
# permissions ($2).
|
|
# Returns 0 (true) if so, 1 otherwise.
|
|
# ======================================================================
|
|
csih_check_dir_perms()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
if [ ! -e "$1" ]
|
|
then
|
|
csih_warning "Your computer is missing $1".
|
|
return 1
|
|
fi
|
|
|
|
if ! csih_path_supports_acls "$1"
|
|
then
|
|
_csih_warning_for_missing_ACL_support "$1"
|
|
csih_warning "Continuing, but something might break..."
|
|
return 0
|
|
fi
|
|
|
|
if /usr/bin/stat -c "%A" "$1" | /usr/bin/grep -Eq ^"$2"
|
|
then
|
|
true
|
|
else
|
|
csih_warning "The permissions on the directory $1 are not correct."
|
|
csih_warning "They must match the regexp $2"
|
|
return 1
|
|
fi
|
|
} # === End of csih_check_dir_perms() === #
|
|
readonly -f csih_check_dir_perms
|
|
|
|
# ======================================================================
|
|
# Routine: csih_check_access
|
|
# Check to see that the owner and Administrators have
|
|
# proper access to the file or directory.
|
|
# $1 -- the file or directory to check
|
|
# $2 -- three character symbolic permissions: 'rwx'. '.w.', etc.
|
|
# On installations older than Windows 2003 and Vista, allow access
|
|
# by System
|
|
# NOTE: must call csih_get_system_and_admins_ids first
|
|
# ======================================================================
|
|
csih_check_access()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local file="$1"
|
|
local perm="$2"
|
|
local msg="$3"
|
|
local notify=0;
|
|
local ls_result="$(/usr/bin/ls -dLln "$file" 2> /dev/null)"
|
|
|
|
if [ -z "$csih_ADMINSGID" ]
|
|
then
|
|
csih_get_system_and_admins_ids
|
|
if [ $? -ne 0 ]
|
|
then
|
|
return $?
|
|
fi
|
|
fi
|
|
|
|
if ! csih_path_supports_acls "$file"
|
|
then
|
|
_csih_warning_for_missing_ACL_support "$fild"
|
|
csih_warning "Continuing, but something might break..."
|
|
return 0
|
|
fi
|
|
|
|
# If the owner of the file does not have access,
|
|
# then notify the user.
|
|
if [ -z "$(echo "$ls_result" | /usr/bin/sed -n /^."$perm"/p)" ]
|
|
then
|
|
notify=1;
|
|
|
|
# If the 'Administrators' group has owner or group access to the file,
|
|
# but does not have the desired access, then notify the user.
|
|
|
|
elif ( [ -n "$csih_ADMINSUID" -a "$(echo "$ls_result" | /usr/bin/awk '{ print $3 }')" -eq $csih_ADMINSUID ] || \
|
|
( ! csih_is_nt2003 && [ -n "$csih_SYSTEMUID" -a "$(echo "$ls_result" | /usr/bin/awk '{ print $3 }')" -eq $csih_SYSTEMUID ] ))
|
|
then
|
|
# Administrators group owns the file, or (on < NT2003,XP64) SYSTEM owns the file
|
|
# this is ok; do nothing.
|
|
true;
|
|
elif ( [ "$(echo "$ls_result" | /usr/bin/awk '{ print $4 }')" -eq $csih_ADMINSGID ] || \
|
|
( ! csih_is_nt2003 && [ "$(echo "$ls_result" | /usr/bin/awk '{ print $4 }')" -eq $csih_SYSTEMGID ] ))
|
|
then
|
|
# The Administrators group has group access to the file, or
|
|
# (on < NT2003,XP64) SYSTEM has group access to the file. Check to
|
|
# see if the chmod bits for group allow these groups to have
|
|
# "owner-like" access to the file. If not, notify.
|
|
[ -z "$(echo "$ls_result" | /usr/bin/sed -n /^...."$perm"/p)" ] && notify=1
|
|
elif ( [ -n "$(/usr/bin/getfacl -n "$file" | /usr/bin/sed -n /^group:"$csih_ADMINSGID":"$perm"/p )" ] || \
|
|
( ! csih_is_nt2003 && [ -n "$(/usr/bin/getfacl -n "$file" | /usr/bin/sed -e /^group:"$csih_SYSTEMGID":"$perm"/p )" ] ))
|
|
then
|
|
# There exists an extended ACL entry for the Administrators (or
|
|
# SYSTEM group, pre NT2003,XP64), with the desired owner-like permissions.
|
|
# This is ok.
|
|
true;
|
|
else
|
|
# otherwise, we do /not/ have sufficient access to the file.
|
|
notify=1
|
|
fi
|
|
|
|
if [ "$notify" -eq 1 ]; then
|
|
csih_warning "The owner and the Administrators need"
|
|
csih_warning "to have $perm permission to $file."
|
|
csih_warning "Here are the current permissions and ACLS:"
|
|
ls_result=$(/usr/bin/ls -dlL "${file}" 2>&1)
|
|
csih_warning " $ls_result"
|
|
/usr/bin/getfacl "${file}" 2>&1 | while read LN
|
|
do
|
|
csih_warning " $LN"
|
|
done
|
|
csih_warning "Please change the user and/or group ownership, "
|
|
csih_warning "permissions, or ACLs of $file."
|
|
echo
|
|
[ -z "${msg}" ] || csih_warning "${msg}"
|
|
return 1;
|
|
fi
|
|
} # === End of csih_check_access() === #
|
|
readonly -f csih_check_access
|
|
|
|
# ======================================================================
|
|
# Routine: csih_check_sys_mount
|
|
# Deprecated. Always return 0.
|
|
# ======================================================================
|
|
csih_check_sys_mount()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
return 0
|
|
} # === End of csih_check_sys_mount() === #
|
|
readonly -f csih_check_sys_mount
|
|
|
|
# ======================================================================
|
|
# DEPRECATED: csih_check_basic_mounts
|
|
# Stub for backward compatibility
|
|
# ======================================================================
|
|
csih_check_basic_mounts()
|
|
{
|
|
csih_warning "$csih_progname_base is using deprecated "\
|
|
"function csih_check_basic_mounts. Continuing..."
|
|
true
|
|
} # === End of csih_check_basic_mounts() === #
|
|
readonly -f csih_check_basic_mounts
|
|
|
|
# ======================================================================
|
|
# Routine: csih_privileged_accounts [-u username]
|
|
# Determines the names of all known "privileged" users already created
|
|
# on this system, or known to this system (e.g. domain users)
|
|
# Checks for cyg_server, sshd_server, cron_server as well as 'username'
|
|
# passed as an argument to the -u option, if specified. The -u username
|
|
# will be preferred over the default names, but of those default names,
|
|
# cyg_server is preferred. However, it is taken on faith that if
|
|
# 'username' exists, it is, in fact, privileged and not an "ordinary" user.
|
|
# Avoids rechecking if already set.
|
|
#
|
|
# SETS GLOBAL (PRIVATE) VARIABLES:
|
|
# _csih_all_preexisting_privileged_accounts
|
|
# _csih_preferred_preexisting_privileged_account
|
|
# ======================================================================
|
|
csih_privileged_accounts()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local opt_username
|
|
local pwd_entries
|
|
local domain
|
|
local username
|
|
local take_it
|
|
local accounts
|
|
local first_account
|
|
|
|
# always parse "command line"
|
|
OPTIND=0
|
|
while getopts ":u:" options; do
|
|
case $options in
|
|
u ) opt_username="$OPTARG" ;;
|
|
\? ) csih_warning "${FUNCNAME[0]} ignoring invalid option: $OPTARG" ;;
|
|
\: ) csih_warning "${FUNCNAME[0]} ignoring option missing required argument: $OPTARG" ;;
|
|
esac
|
|
done
|
|
shift $(($OPTIND - 1))
|
|
[ -n "${1}" ] && opt_servicename="${1}"
|
|
|
|
if [ -z "${_csih_all_preexisting_privileged_accounts}" ]
|
|
then
|
|
# First check optional username from command line
|
|
if [ -n "$opt_username" ]
|
|
then
|
|
pwd_entries=$(/usr/bin/getent -w passwd "$opt_username")
|
|
# Extract Cygwin username and Windows domain
|
|
username="${pwd_entries%%:*}"
|
|
domain="${pwd_entries#*:*:}"
|
|
domain="${domain%\\*}"
|
|
take_it=1
|
|
# Local SAM account? Check privileges
|
|
[ "${COMPUTERNAME,,*}" = "${domain,,*}" ] \
|
|
&& ! csih_account_has_necessary_privileges "$username" && take_it=0
|
|
if [ $take_it -eq 0 ]
|
|
then
|
|
# -u $opt_username does NOT have the required privileges,
|
|
# even though it exists. Warn, and skip
|
|
csih_warning "Privileged account '$opt_username' was specified,"
|
|
csih_warning "but it does not have the necessary privileges."
|
|
csih_warning "Continuing, but will probably use a different account."
|
|
else
|
|
first_account="${username}"
|
|
accounts="'${username}' "
|
|
fi
|
|
fi
|
|
# Then check predefined Cygwin service accounts
|
|
pwd_entries=$(/usr/bin/getent passwd $_csih_well_known_privileged_accounts \
|
|
| /usr/bin/cut -d: -f 1)
|
|
for username in $pwd_entries
|
|
do
|
|
[ -z "${first_account}" ] && first_account="${username}"
|
|
accounts="${accounts}'${username}' "
|
|
done
|
|
if [ -n "${accounts}" ]
|
|
then
|
|
_csih_all_preexisting_privileged_accounts="${accounts}"
|
|
_csih_preferred_preexisting_privileged_account="${first_account}"
|
|
fi
|
|
fi
|
|
} # === End of csih_privileged_accounts() === #
|
|
readonly -f csih_privileged_accounts
|
|
|
|
# ======================================================================
|
|
# Routine: csih_privileged_account_exists
|
|
# On Windows NT and above, determines if the specified
|
|
# user ${1} exists and is one of the well-known privileged users
|
|
# (cyg_server, sshd_server, cron_server), or actually does possess
|
|
# the required privileges.
|
|
# Returns 0 (true) if so, 1 otherwise.
|
|
# ======================================================================
|
|
csih_privileged_account_exists()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
csih_privileged_accounts -u "$1"
|
|
if [ -n "${_csih_all_preexisting_privileged_accounts}" ]
|
|
then
|
|
case "${_csih_all_preexisting_privileged_accounts}" in
|
|
*" '$1' "* | "'$1' "* | *" '$1'" | "'$1'") true;;
|
|
*) false;;
|
|
esac
|
|
else
|
|
false
|
|
fi
|
|
} # === End of csih_privileged_account_exists() === #
|
|
readonly -f csih_privileged_account_exists
|
|
|
|
# ======================================================================
|
|
# Routine: csih_account_has_necessary_privileges
|
|
# On Windows NT and above, checks whether the specified account $1
|
|
# has the privileges necessary to change user contexts.
|
|
# Returns 0 (true) if so, 1 otherwise.
|
|
# Also returns false if $1 is unspecified, or $1 doesn't exist.
|
|
# ======================================================================
|
|
csih_account_has_necessary_privileges() {
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
|
|
local user="$1"
|
|
if [ -n "${user}" ]
|
|
then
|
|
if ! csih_check_program_or_warn /usr/bin/editrights editrights
|
|
then
|
|
csih_warning "The 'editrights' program cannot be found or is not executable."
|
|
csih_warning "Unable to ensure that '${user}' has the appropriate privileges."
|
|
return 1
|
|
else
|
|
# Don't attempt to validate membership in Administrators group
|
|
# Instead, just try to set the appropriate rights; if it fails
|
|
# then handle that, instead.
|
|
/usr/bin/editrights -u "${user}" -t SeAssignPrimaryTokenPrivilege >/dev/null 2>&1 &&
|
|
/usr/bin/editrights -u "${user}" -t SeCreateTokenPrivilege >/dev/null 2>&1 &&
|
|
/usr/bin/editrights -u "${user}" -t SeTcbPrivilege >/dev/null 2>&1 &&
|
|
/usr/bin/editrights -u "${user}" -t SeServiceLogonRight >/dev/null 2>&1
|
|
return # status of previous command-list
|
|
fi
|
|
fi
|
|
false
|
|
} # === End of csih_account_has_necessary_privileges() === #
|
|
readonly -f csih_account_has_necessary_privileges
|
|
|
|
|
|
# ======================================================================
|
|
# Routine: _csih_setup
|
|
# Basic checks for all clients of this script. It is the final
|
|
# initialization phase for csih, and unlike the other phases -- which
|
|
# execute as soon as csih is sourced by the client script -- this
|
|
# initialization is peformed at "runtime". That is, it is called
|
|
# internally by any "public" API function for which the initialiation
|
|
# is needed.
|
|
#
|
|
# _csih_setup internally handles repeated calls, and initialization
|
|
# is skipped if already performed.
|
|
#
|
|
# Exits if anything is wrong.
|
|
# ======================================================================
|
|
_csih_setup()
|
|
{
|
|
local uid
|
|
local gid
|
|
local user_sid
|
|
local grp_sid
|
|
local perms="d..x..x..[xt]"
|
|
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
if [ "$_csih_setup_already_called" -eq 0 ]
|
|
then
|
|
|
|
if [ -z "${SYSCONFDIR}" ]
|
|
then
|
|
csih_error "Variable SYSCONFDIR is empty (should be '/etc' ?)"
|
|
fi
|
|
|
|
if [ -z "${LOCALSTATEDIR}" ]
|
|
then
|
|
csih_error "Variable LOCALSTATEDIR is empty (should be '/var' ?)"
|
|
fi
|
|
|
|
if ! csih_get_system_and_admins_ids
|
|
then
|
|
csih_error "Problem with LocalSystem or Adminstrator IDs"
|
|
fi
|
|
|
|
uid=$(/usr/bin/stat -c '%u' ${LOCALSTATEDIR})
|
|
gid=$(/usr/bin/stat -c '%g' ${LOCALSTATEDIR})
|
|
user_sid=$(/usr/bin/getent -w passwd $uid | awk -F: '{print $4}')
|
|
grp_sid=$(/usr/bin/getent -w group $gid | awk -F: '{print $4}')
|
|
|
|
if [ "${user_sid}" = "${grp_sid}" ]
|
|
then
|
|
perms="d..x.....[xt]"
|
|
fi
|
|
|
|
if ! csih_check_dir_perms "${LOCALSTATEDIR}" "${perms}"
|
|
then
|
|
csih_error "Problem with ${LOCALSTATEDIR} directory. Exiting."
|
|
fi
|
|
|
|
# attempt to set permissions, but not an error if fail
|
|
# will verify that we actually HAVE correct permissions below.
|
|
csih_make_dir "${LOCALSTATEDIR}/run"
|
|
/usr/bin/chmod 1777 "${LOCALSTATEDIR}/run" >&/dev/null || true
|
|
/usr/bin/setfacl -m u:system:rwx "${LOCALSTATEDIR}/run" >&/dev/null || true
|
|
/usr/bin/setfacl -m g:544:rwx "${LOCALSTATEDIR}/run" >&/dev/null || true
|
|
|
|
csih_make_dir "${LOCALSTATEDIR}/log"
|
|
/usr/bin/chmod 1777 "${LOCALSTATEDIR}/log" >&/dev/null || true
|
|
/usr/bin/setfacl -m u:system:rwx "${LOCALSTATEDIR}/log" >&/dev/null || true
|
|
/usr/bin/setfacl -m g:544:rwx "${LOCALSTATEDIR}/log" >&/dev/null || true
|
|
|
|
csih_make_dir "${LOCALSTATEDIR}/empty"
|
|
/usr/bin/chmod 755 "${LOCALSTATEDIR}/empty" >&/dev/null || true
|
|
/usr/bin/setfacl -m u:system:r-x "${LOCALSTATEDIR}/empty" >&/dev/null || true
|
|
/usr/bin/setfacl -m g:544:r-x "${LOCALSTATEDIR}/empty" >&/dev/null || true
|
|
|
|
# daemons need write access to /var/run to create pid file
|
|
if ! csih_check_access "${LOCALSTATEDIR}/run" .w.
|
|
then
|
|
csih_error "Problem with ${LOCALSTATEDIR}/run directory. Exiting."
|
|
fi
|
|
# daemons need write access to /var/log if they do their own logging
|
|
if ! csih_check_access "${LOCALSTATEDIR}/log" .w.
|
|
then
|
|
csih_error "Problem with ${LOCALSTATEDIR}/log directory. Exiting."
|
|
fi
|
|
# daemons need access to /var/empty for chrooting
|
|
if ! csih_check_access "${LOCALSTATEDIR}/empty" r.x
|
|
then
|
|
csih_error "Problem with ${LOCALSTATEDIR}/empty directory. Exiting."
|
|
fi
|
|
|
|
# just ensure that /etc exists. It is up to clients of this
|
|
# script to explicitly check accees to the specific configuration
|
|
# files inside /etc...
|
|
csih_make_dir "${SYSCONFDIR}"
|
|
/usr/bin/chmod 755 "${SYSCONFDIR}" >&/dev/null || true
|
|
|
|
_csih_setup_already_called=1
|
|
fi
|
|
} # === End of _csih_setup() === #
|
|
readonly -f _csih_setup
|
|
|
|
# ======================================================================
|
|
# Routine: csih_old_cygwin
|
|
# Check Cygwin version, account databases are avaiable since 1.7.34
|
|
# On Cygwin versions <= 1.7.33 return 0
|
|
# On Cygwin versions > 1.7.33 return 1
|
|
# ======================================================================
|
|
csih_old_cygwin()
|
|
{
|
|
local old_cygwin
|
|
|
|
/usr/bin/uname -r |
|
|
/usr/bin/awk -F. '{
|
|
if ( $1 < 1 || \
|
|
($1 == 1 && $2 < 7) || \
|
|
($1 == 1 && $2 == 7 && strtonum($3) <= 33))
|
|
exit 0;
|
|
exit 1;
|
|
}'
|
|
old_cygwin=$?
|
|
return ${old_cygwin}
|
|
} # === End of csih_old_cygwin() === #
|
|
readonly -f csih_old_cygwin
|
|
|
|
# ======================================================================
|
|
# Routine: csih_use_file_etc passwd|group
|
|
# Check if /etc/passwd or /etc/group file is in use.
|
|
# On Cygwin versions < 1.7.33, files are always used.
|
|
# On Cygwin versions >= 1.7.33 it depends on /etc/nsswitch.conf.
|
|
#
|
|
# If /etc/nsswitch.conf doesn't exit, "db" is used and we don't
|
|
# need the files.
|
|
#
|
|
# If /etc/nsswitch.conf exists, and passwd/group lines contain
|
|
# the "db" entry, "db" is used and we don't need the files.
|
|
#
|
|
# If /etc/nsswitch.conf exists, and no passwd/group lines are
|
|
# present, "db" is used by default and we don't need the files.
|
|
#
|
|
# Otherwise, we need the files.
|
|
#
|
|
# Returns 1 if files shall be used, 0 otherwise.
|
|
# ======================================================================
|
|
csih_use_file_etc()
|
|
{
|
|
local file="$1"
|
|
local use_file
|
|
|
|
if [ "$file" != "passwd" -a "$file" != "group" ]
|
|
then
|
|
csih_error 'Script error: csih_use_file_etc requires argument "passwd" or "group".'
|
|
fi
|
|
csih_old_cygwin ; use_file=$?
|
|
if [ ${use_file} -ne 0 -a -f /etc/nsswitch.conf ]
|
|
then
|
|
if grep -Eq "^${file}:" /etc/nsswitch.conf
|
|
then
|
|
grep -Eq "^${file}:[^#]*\<db\>" /etc/nsswitch.conf || use_file=0
|
|
fi
|
|
fi
|
|
return ${use_file}
|
|
} # === End of csih_use_file_etc() === #
|
|
readonly -f csih_use_file_etc
|
|
|
|
# ======================================================================
|
|
# Routine: csih_select_privileged_username [-q] [-f] [-u default_user] [service_name]
|
|
# On NT and above, get the desired privileged account name.
|
|
#
|
|
# If the optional argument '-q' is specified, then this function will
|
|
# operate in query mode, which is more appropriate for user-config
|
|
# scripts that need information ABOUT a service, but do not
|
|
# themselves install the service.
|
|
#
|
|
# If the optional argument '-f' is specified, then no confirmation
|
|
# questions will be asked about the selected username. This is
|
|
# useful mainly in unattended installations.
|
|
#
|
|
# If the optional argument '-u' is specified, then the next
|
|
# argument will be used as the "privileged" username -- UNLESS
|
|
# [service_name] is provided, and that service is already
|
|
# installed under some OTHER username. In the latter case, the
|
|
# current user under which [service_name] is installed will be
|
|
# used, and the value specified by -u will be IGNORED.
|
|
#
|
|
# If the optional [service_name] argument is present, then that value
|
|
# may be used in some of the messages. Also, this function will
|
|
# then check to see if [service_name] is already installed. If so,
|
|
# the account under which it is installed will be selected, assuming
|
|
# it passes validation (has necessary permissions, group memberships,
|
|
# etc)
|
|
#
|
|
# Usually [service_name] and [-q] should be specified together.
|
|
# [-f] can be set regardless of other options.
|
|
#
|
|
# SETS GLOBAL VARIABLE:
|
|
# csih_PRIVILEGED_USERNAME
|
|
# csih_PRIVILEGED_USERWINNAME
|
|
# csih_PRIVILEGED_USERDOMAIN
|
|
# OPTIND
|
|
# OPTARG
|
|
#
|
|
# csih_auto_answer=no behavior
|
|
# if [service_name] and [-q] and [service_name] is installed
|
|
# get account under which it is installed
|
|
# validate account (may issue error!)
|
|
# use that account name
|
|
# elif $default_username is specified, exists, and has necessary privileges,
|
|
# use $default_username
|
|
# elif any(cyg_server cron_server sshd_server) exists,
|
|
# use first in list
|
|
# else
|
|
# if csih_is_nt2003 || csih_FORCE_PRIVILEGED_USER # note: csih_is_nt2003 true for XP64 too
|
|
# if $default_username is specified
|
|
# use $default_username
|
|
# else
|
|
# use cyg_server
|
|
# else
|
|
# do nothing (csih_PRIVILEGED_USERNAME="")
|
|
#
|
|
# ======================================================================
|
|
csih_select_privileged_username()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local domain
|
|
local winusername
|
|
local username
|
|
local newname
|
|
local opt_query=0
|
|
local opt_force=0
|
|
local opt_servicename=""
|
|
local opt_default_username=""
|
|
local options
|
|
local theservice
|
|
local map_entry
|
|
local use_files
|
|
|
|
_csih_setup
|
|
|
|
# always parse "command line"
|
|
OPTIND=0
|
|
while getopts ":qfu:" options; do
|
|
case $options in
|
|
q ) opt_query=1 ;;
|
|
f ) opt_force=1 ;;
|
|
u ) opt_default_username="$OPTARG" ;;
|
|
\? ) csih_warning "${FUNCNAME[0]} ignoring invalid option: $OPTARG" ;;
|
|
\: ) csih_warning "${FUNCNAME[0]} ignoring option missing required argument: $OPTARG" ;;
|
|
esac
|
|
done
|
|
shift $(($OPTIND - 1))
|
|
[ -n "${1}" ] && opt_servicename="${1}"
|
|
|
|
# save time if csih_PRIVILEGED_USERNAME already set
|
|
if [ -n "${csih_PRIVILEGED_USERNAME}" ]
|
|
then
|
|
return
|
|
fi
|
|
|
|
csih_privileged_accounts -u "$opt_default_username"
|
|
|
|
# if query mode and opt_servicename has been specified,
|
|
# first check to see if the service has already been
|
|
# installed. If so, get the service's account name.
|
|
# If (and only if) that account is privileged, then
|
|
# record it in csih_PRIVILEGED_USERNAME.
|
|
if [ $opt_query -ne 0 -a -n "${opt_servicename}" ]
|
|
then
|
|
if /usr/bin/cygrunsrv -Q "${opt_servicename}" >/dev/null 2>&1
|
|
then
|
|
username=$(/usr/bin/cygrunsrv -V -Q "${opt_servicename}" 2>&1 | /usr/bin/sed -n -e '/^Account/s/^.* : //p')
|
|
domain="${username%\\*}"
|
|
winusername="${username#*\\}"
|
|
if [ "${winusername}" = "LocalSystem" ]
|
|
then
|
|
username=#empty; SYSTEM is not a "privileged user"
|
|
else
|
|
username=$(/usr/bin/getent passwd "${winusername}" "${domain}+${winusername}" | /usr/bin/head -n1 | /usr/bin/cut -d: -f 1)
|
|
fi
|
|
if [ -n "${username}" ]
|
|
then
|
|
if csih_privileged_account_exists "${username}"
|
|
then
|
|
# ${opt_servicename} is installed under account "${username}",
|
|
# which is one of the pre-declared privileged users -- or,
|
|
# we have already validated that ${username} has the necessary
|
|
# privilegeds. Great!
|
|
csih_PRIVILEGED_USERNAME="${username}"
|
|
csih_PRIVILEGED_USERWINNAME="${winusername}"
|
|
csih_PRIVILEGED_USERDOMAIN="${domain}"
|
|
return
|
|
else
|
|
if csih_account_has_necessary_privileges "${username}"
|
|
then
|
|
# ${opt_servicename} is installed under account "${username}",
|
|
# but ${username} is not one of the pre-declared privileged users
|
|
# (cyg_server, sshd_server, cron_server) -- nor had we previously
|
|
# validated that it has the necessary privileges. However, we just
|
|
# did validate that, and it DOES have the necessary privileges.
|
|
# Add it to the list.
|
|
csih_PRIVILEGED_USERNAME="${username}"
|
|
csih_PRIVILEGED_USERWINNAME="${winusername}"
|
|
csih_PRIVILEGED_USERDOMAIN="${domain}"
|
|
_csih_all_preexisting_privileged_accounts="${_csih_all_preexisting_privileged_accounts}'${username}' "
|
|
return
|
|
else
|
|
# ${opt_servicename} is installed under account "${username}", but
|
|
# ${username} is not one of the pre-declared privileged users
|
|
# (cyg_server, sshd_server, cron_server), nor does it have the
|
|
# necessary privileges. Ignore it...
|
|
return
|
|
fi
|
|
fi # privileged_user_exists
|
|
else
|
|
# ${opt_servicename} installed under LocalSystem, or there was
|
|
# some error in determining the account name under which it is installed.
|
|
return
|
|
fi # $username empty
|
|
fi # ${opt_servicename} is not installed
|
|
fi # not (opt_query && opt_servicename)
|
|
|
|
if [ $opt_query -eq 0 ]
|
|
then
|
|
if csih_is_nt2003
|
|
then
|
|
csih_inform "It's not possible to use the LocalSystem account for services"
|
|
csih_inform "that can change the user id without an explicit password"
|
|
csih_inform "(such as passwordless logins [e.g. public key authentication]"
|
|
csih_inform "via sshd) when having to create the user token from scratch."
|
|
csih_inform "For more information on this requirement, see"
|
|
csih_inform "https://cygwin.com/cygwin-ug-net/ntsec.html#ntsec-nopasswd1"
|
|
echo ""
|
|
csih_inform "If you want to enable that functionality, it's required to create"
|
|
csih_inform "a new account with special privileges (unless such an account"
|
|
csih_inform "already exists). This account is then used to run these special"
|
|
csih_inform "servers."
|
|
echo ""
|
|
csih_inform "Note that creating a new user requires that the current account"
|
|
csih_inform "have Administrator privileges itself."
|
|
elif [ "x$csih_FORCE_PRIVILEGED_USER" = "xyes" ]
|
|
then
|
|
csih_inform "You have requested that a special privileged user be used"
|
|
csih_inform "by the service, and are running on 32 bit Windows XP"
|
|
csih_inform "where this is not actually required (LocalSystem would also work)."
|
|
echo ""
|
|
csih_inform "Note that creating a new user requires that the current account"
|
|
csih_inform "have Administrator privileges itself."
|
|
else
|
|
# hmm. XP(32), but not csih_FORCE_PRIVILEGED_USER
|
|
# in this case, we emit no messages. If a privileged
|
|
# user already exists, we'll use it. Otherwise, don't
|
|
# specify a "privileged" user. Callers will know to
|
|
# silently use LocalSystem.
|
|
:
|
|
fi
|
|
fi
|
|
|
|
if [ -n "${_csih_all_preexisting_privileged_accounts}" -a -z "$opt_default_username" ]
|
|
then
|
|
echo ""
|
|
csih_inform "The following privileged accounts were found: ${_csih_all_preexisting_privileged_accounts}."
|
|
username="${_csih_preferred_preexisting_privileged_account}"
|
|
else
|
|
if ( csih_is_nt2003 || [ "x$csih_FORCE_PRIVILEGED_USER" = "xyes" ] )
|
|
then
|
|
if [ $opt_query -eq 0 -a -z "$opt_default_username" ]
|
|
then
|
|
echo ""
|
|
csih_inform "No privileged account could be found."
|
|
fi
|
|
if [ -n "$opt_default_username" ]
|
|
then
|
|
username="$opt_default_username"
|
|
else
|
|
username="cyg_server"
|
|
fi
|
|
else
|
|
# nt/2k/xp32 and not csih_FORCE_PRIVILEGED_USER and username is empty
|
|
# we couldn't find a pre-existing privileged user, but we don't
|
|
# really need one (nt/2k/xp32) and haven't explicitly requested one
|
|
# via csih_FORCE... In this case, we're done: just return. (this
|
|
# is true regardless of the value of $opt_query)
|
|
return
|
|
fi
|
|
fi
|
|
|
|
# if we get here, then $username WILL be set to something
|
|
if [ $opt_query -eq 0 ]
|
|
then
|
|
echo ""
|
|
csih_inform "This script plans to use '${username}'."
|
|
csih_inform "'${username}' will only be used by registered services."
|
|
if [ $opt_force -eq 0 ]
|
|
then
|
|
if csih_request "Do you want to use a different name?"
|
|
then
|
|
csih_get_value "Enter the new user name:"
|
|
username="${csih_value}"
|
|
fi
|
|
fi
|
|
else
|
|
theservice=${opt_servicename:-the service}
|
|
csih_inform "This script will assume that ${theservice} will run"
|
|
csih_inform "under the '${username}' account."
|
|
if [ $opt_force -eq 0 ]
|
|
then
|
|
if csih_request "Will ${theservice} run under a different account?"
|
|
then
|
|
csih_get_value "Enter the user name used by the service:"
|
|
username="${csih_value}"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# faster than checking SAM -- see if username is one that we
|
|
# already know about
|
|
if csih_privileged_account_exists "$username"
|
|
then
|
|
_csih_preferred_preexisting_privileged_account="${username}"
|
|
else
|
|
# perhaps user specified a pre-existing privileged account we
|
|
# don't know about
|
|
if /usr/bin/getent passwd "${username}" >/dev/null 2>&1
|
|
then
|
|
if ! csih_account_has_necessary_privileges "${username}"
|
|
then
|
|
csih_warning "The specified account '${username}' does not have the"
|
|
csih_warning "required permissions or group memberships. This may"
|
|
csih_warning "cause problems if not corrected; continuing..."
|
|
elif [ ${opt_query} -eq 0 ]
|
|
then
|
|
csih_inform "'${username}' already exists...and has all necessary permissions."
|
|
fi
|
|
# so, add it to our list, so that csih_privileged_account_exists
|
|
# will return true...
|
|
_csih_preferred_preexisting_privileged_account="${username}"
|
|
_csih_all_preexisting_privileged_accounts="${_csih_all_preexisting_privileged_accounts}'${username}' "
|
|
fi
|
|
# if it doesn't exist, we're probably in the midst of creating it.
|
|
# so don't issue any warnings.
|
|
fi
|
|
|
|
map_entry=$(/usr/bin/getent -w passwd "${username}")
|
|
if [ -n "${map_entry}" ]
|
|
then
|
|
local dw
|
|
|
|
csih_PRIVILEGED_USERNAME="${map_entry%%:*}"
|
|
dw="${map_entry#*:*:}"
|
|
dw="${dw%:*}"
|
|
csih_PRIVILEGED_USERDOMAIN="${dw%\\*}"
|
|
csih_PRIVILEGED_USERWINNAME="${dw#*\\}"
|
|
else
|
|
csih_PRIVILEGED_USERNAME="${username}"
|
|
if ! csih_use_file_etc "passwd"
|
|
then
|
|
# This test succeeds on domain member machines only, not on DCs.
|
|
if [ "${USERDOMAIN,,*}" != "${COMPUTERNAME,,*}" \
|
|
-o "$(/usr/bin/mkpasswd -c | /usr/bin/awk -F: '{print $1}')" = "${USERDOMAIN}+${USERNAME}" ]
|
|
then
|
|
# Lowercase of USERDOMAIN
|
|
csih_PRIVILEGED_USERNAME="${COMPUTERNAME,,*}+${username}"
|
|
fi
|
|
fi
|
|
csih_PRIVILEGED_USERDOMAIN="${COMPUTERNAME}"
|
|
csih_PRIVILEGED_USERWINNAME="${username}"
|
|
fi
|
|
|
|
} # === End of csih_select_privileged_username() === #
|
|
readonly -f csih_select_privileged_username
|
|
|
|
|
|
# ======================================================================
|
|
# Routine: csih_create_privileged_user
|
|
# On 64bit Windows XP, Windows Server 2003 and above (including Windows
|
|
# Vista), or if csih_FORCE_PRIVILEGED_USER == "yes" for Windows NT and
|
|
# above, allows user to select a pre-existing privileged user, or to
|
|
# create a new privileged user.
|
|
# $1 (optional) will be used as the password if non-empty
|
|
#
|
|
# NOTE: For using special behaviours triggered by optional parameters
|
|
# to the csih_select_privileged_username function, you should first
|
|
# call that function with all required parameters, and then call this
|
|
# function. The selected username will already be stored in
|
|
# $csih_PRIVILEGED_USERNAME.
|
|
#
|
|
# Exits on catastrophic error (or if user enters empty password)
|
|
# Returns 0 on total success
|
|
# Returns 1 on partial success (created user, but could not add
|
|
# to admin group, or set privileges, etc). Recommend caller
|
|
# check return value, and offer user opportunity to quit.
|
|
#
|
|
# On success, the username and password will be available in
|
|
# csih_PRIVILEGED_USERNAME
|
|
# csih_PRIVILEGED_USERDOMAIN
|
|
# csih_PRIVILEGED_USERWINNAME
|
|
# csih_PRIVILEGED_PASSWORD
|
|
#
|
|
# csih_auto_answer=no behavior
|
|
# if csih_is_nt2003 || FORCE # note: csih_is_nt2003 is true for XP64, too
|
|
# if pre-existing privileged user
|
|
# make sure its group membership and perms are correct
|
|
# else
|
|
# do nothing, return 1
|
|
# else
|
|
# do nothing, return 1
|
|
# ======================================================================
|
|
csih_create_privileged_user()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local username_in_sam
|
|
local admingroup
|
|
local dos_var_empty
|
|
local _password
|
|
local password_value="$1"
|
|
local passwd_has_expiry_flags
|
|
local ret=0
|
|
local username_in_admingroup
|
|
local username_got_all_rights
|
|
local tmpfile1
|
|
|
|
_csih_setup
|
|
csih_select_privileged_username
|
|
|
|
if ( csih_is_nt2003 || [ "x$csih_FORCE_PRIVILEGED_USER" = "xyes" ] )
|
|
then
|
|
if ! csih_privileged_account_exists "$csih_PRIVILEGED_USERNAME"
|
|
then
|
|
username_in_sam=no
|
|
|
|
# give auto-answer a chance to veto, because we can't enter password
|
|
# from setup.exe...
|
|
if csih_request "Create new privileged user account '${csih_PRIVILEGED_USERDOMAIN}\\\\${csih_PRIVILEGED_USERWINNAME}' (Cygwin name: '${csih_PRIVILEGED_USERNAME}')?"
|
|
then
|
|
dos_var_empty=$(/usr/bin/cygpath -w ${LOCALSTATEDIR}/empty)
|
|
|
|
if [ -n "${password_value}" ]
|
|
then
|
|
_password="${password_value}"
|
|
# Allow to ask for password if first try fails
|
|
password_value=""
|
|
else
|
|
csih_inform "Please enter a password for new user ${csih_PRIVILEGED_USERNAME}. Please be sure"
|
|
csih_inform "that this password matches the password rules given on your system."
|
|
csih_inform "Entering no password will exit the configuration."
|
|
csih_get_value "Please enter the password:" -s
|
|
_password="${csih_value}"
|
|
if [ -z "${_password}" ]
|
|
then
|
|
csih_error_multi "Exiting configuration. No user ${csih_PRIVILEGED_USERNAME} has been created," \
|
|
"and no services have been installed."
|
|
fi
|
|
fi
|
|
tmpfile1=$(csih_mktemp) || csih_error "Could not create temp file"
|
|
csih_call_winsys32 net user "${csih_PRIVILEGED_USERWINNAME}" \
|
|
"${_password}" \
|
|
/fullname:"Privileged server" \
|
|
/homedir:"${dos_var_empty}" \
|
|
/comment:'<cygwin home="/var/empty" shell="/bin/false"/>' \
|
|
/add /yes > "${tmpfile1}" 2>&1 && username_in_sam=yes
|
|
if [ "${username_in_sam}" != "yes" ]
|
|
then
|
|
csih_warning "Creating the user '${csih_PRIVILEGED_USERNAME}' failed! Reason:"
|
|
/usr/bin/cat "${tmpfile1}"
|
|
echo
|
|
fi
|
|
/usr/bin/rm -f "${tmpfile1}"
|
|
|
|
if [ "${username_in_sam}" = "yes" ]
|
|
then
|
|
csih_PRIVILEGED_PASSWORD="${_password}"
|
|
csih_inform "User '${csih_PRIVILEGED_USERNAME}' has been created with password '${_password}'."
|
|
csih_inform "If you change the password, please remember also to change the"
|
|
csih_inform "password for the installed services which use (or will soon use)"
|
|
csih_inform "the '${csih_PRIVILEGED_USERNAME}' account."
|
|
echo ""
|
|
|
|
# If we use /etc account DB only, write new account to /etc/passwd
|
|
if csih_use_file_etc passwd
|
|
then
|
|
/usr/bin/mkpasswd -l -u "${csih_PRIVILEGED_USERNAME}" >> "${SYSCONFDIR}/passwd"
|
|
fi
|
|
|
|
if ! passwd -e "${csih_PRIVILEGED_USERNAME}" >/dev/null
|
|
then
|
|
csih_warning "Setting password expiry for user '${csih_PRIVILEGED_USERNAME}' failed!"
|
|
csih_warning "Please check that password never expires or set it to your needs."
|
|
fi
|
|
fi
|
|
fi # user allowed us to create account
|
|
else
|
|
# ${csih_PRIVILEGED_USERNAME} already exists. Use it, and make no changes.
|
|
# use passed-in value as first guess
|
|
csih_PRIVILEGED_PASSWORD="${password_value}"
|
|
return 0
|
|
fi
|
|
|
|
# Username did NOT previously exist, but has been successfully created.
|
|
# set group memberships, privileges, and passwd timeout.
|
|
if [ "$username_in_sam" = "yes" ]
|
|
then
|
|
# always try to set group membership and privileges
|
|
admingroup=$(/usr/bin/getent -w group S-1-5-32-544)
|
|
admingroup="${admingroup#*:*:*\\}"
|
|
admingroup="${admingroup%:*}"
|
|
if [ -z "${admingroup}" ]
|
|
then
|
|
csih_warning "Cannot obtain the Administrators group name from 'getent -w'."
|
|
ret=1
|
|
elif csih_call_winsys32 net localgroup "${admingroup}" | /usr/bin/grep -Eiq "^${csih_PRIVILEGED_USERWINNAME}.?$"
|
|
then
|
|
true
|
|
else
|
|
csih_call_winsys32 net localgroup "${admingroup}" "${csih_PRIVILEGED_USERWINNAME}" /add > /dev/null 2>&1 && username_in_admingroup=yes
|
|
if [ "${username_in_admingroup}" != "yes" ]
|
|
then
|
|
csih_warning "Adding user '${csih_PRIVILEGED_USERNAME}' to local group '${admingroup}' failed!"
|
|
csih_warning "Please add '${csih_PRIVILEGED_USERNAME}' to local group '${admingroup}' before"
|
|
csih_warning "starting any of the services which depend upon this user!"
|
|
ret=1
|
|
fi
|
|
fi
|
|
|
|
if ! csih_check_program_or_warn /usr/bin/editrights editrights
|
|
then
|
|
csih_warning "The 'editrights' program cannot be found or is not executable."
|
|
csih_warning "Unable to ensure that '${csih_PRIVILEGED_USERNAME}' has the appropriate privileges."
|
|
ret=1
|
|
else
|
|
/usr/bin/editrights -a SeAssignPrimaryTokenPrivilege -u ${csih_PRIVILEGED_USERNAME} &&
|
|
/usr/bin/editrights -a SeCreateTokenPrivilege -u ${csih_PRIVILEGED_USERNAME} &&
|
|
/usr/bin/editrights -a SeTcbPrivilege -u ${csih_PRIVILEGED_USERNAME} &&
|
|
/usr/bin/editrights -a SeDenyInteractiveLogonRight -u ${csih_PRIVILEGED_USERNAME} &&
|
|
/usr/bin/editrights -a SeDenyRemoteInteractiveLogonRight -u ${csih_PRIVILEGED_USERNAME} &&
|
|
/usr/bin/editrights -a SeServiceLogonRight -u ${csih_PRIVILEGED_USERNAME} &&
|
|
username_got_all_rights="yes"
|
|
if [ "${username_got_all_rights}" != "yes" ]
|
|
then
|
|
csih_warning "Assigning the appropriate privileges to user '${csih_PRIVILEGED_USERNAME}' failed!"
|
|
ret=1
|
|
fi
|
|
fi
|
|
|
|
return "${ret}"
|
|
fi # ! username_in_sam
|
|
return 1 # failed to create user (or prevented by auto-answer veto)
|
|
fi # csih_is_nt2003 (also XP64) || csih_FORCE_PRIVILEGED_USER
|
|
return 1 # nt/2k/xp32 without FORCE
|
|
} # === End of csih_create_privileged_user() === #
|
|
readonly -f csih_create_privileged_user
|
|
|
|
# ======================================================================
|
|
# Routine: csih_create_unprivileged_user
|
|
# Creates a new (unprivileged) user as specified by $1.
|
|
# Useful for running services that do not require elevated privileges,
|
|
# or running servers like sshd in "privilege separation" mode.
|
|
#
|
|
# Exits on catastrophic error
|
|
# Returns 0 on total success
|
|
# Returns 1 on failure
|
|
#
|
|
# csih_auto_answer=no behavior
|
|
# if already exists
|
|
# use it
|
|
# else
|
|
# do nothing, return 1
|
|
# ======================================================================
|
|
csih_create_unprivileged_user()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local unpriv_user="$1"
|
|
local map_entry
|
|
local user_exists=no
|
|
local dos_var_empty=
|
|
|
|
_csih_setup
|
|
|
|
map_entry="$(/usr/bin/getent -w passwd "U-${unpriv_user}")"
|
|
if [ -n "${map_entry}" ]
|
|
then
|
|
user_exists=yes
|
|
else
|
|
csih_inform "Note that creating a new user requires that the current account have"
|
|
csih_inform "Administrator privileges. Should this script attempt to create a"
|
|
# give auto-answer a chance to veto
|
|
if csih_request "new local account '${unpriv_user}'?"
|
|
then
|
|
dos_var_empty=$(/usr/bin/cygpath -w ${LOCALSTATEDIR}/empty)
|
|
csih_call_winsys32 net user "${unpriv_user}" \
|
|
/homedir:"${dos_var_empty}" \
|
|
/comment:'<cygwin home="/var/empty" shell="/bin/false"/>' \
|
|
/add /active:no >/dev/null 2>&1 && user_exists=yes
|
|
if [ "${user_exists}" != "yes" ]
|
|
then
|
|
csih_warning "Creating the user '${unpriv_user}' failed!"
|
|
else
|
|
# If we use /etc account DB only, write new account to /etc/passwd
|
|
if csih_use_file_etc passwd
|
|
then
|
|
/usr/bin/mkpasswd -l -u "${unpriv_user}" >> "${SYSCONFDIR}/passwd"
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ "${user_exists}" = "yes" ]
|
|
then
|
|
local dw
|
|
|
|
map_entry="$(/usr/bin/getent -w passwd "U-${unpriv_user}")"
|
|
csih_UNPRIVILEGED_USERNAME="${map_entry%%:*}"
|
|
dw="${map_entry#*:*:}"
|
|
dw="${dw%:*}"
|
|
csih_UNPRIVILEGED_USERDOMAIN="${dw%\\*}"
|
|
csih_UNPRIVILEGED_USERWINNAME="${dw#*\\}"
|
|
return 0
|
|
fi
|
|
return 1
|
|
} # === End of csih_create_unprivileged_user() === #
|
|
readonly -f csih_create_unprivileged_user
|
|
|
|
# ======================================================================
|
|
# Routine: csih_create_local_group
|
|
# Creates a new local group as specified by $1.
|
|
#
|
|
# Exits on catastrophic error
|
|
# Returns 0 on total success
|
|
# Returns 1 on failure
|
|
#
|
|
# csih_auto_answer=no behavior
|
|
# if already exists
|
|
# use it
|
|
# else
|
|
# do nothing, return 1
|
|
# ======================================================================
|
|
csih_create_local_group()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local group="$1"
|
|
local map_entry
|
|
local grp_exists=no
|
|
|
|
_csih_setup
|
|
|
|
map_entry="$(/usr/bin/getent -w group "U-${group}")"
|
|
if [ -n "${map_entry}" ]
|
|
then
|
|
grp_exists=yes
|
|
else
|
|
csih_inform "Note that creating a new local group requires that the current account have"
|
|
csih_inform "Administrator privileges. Should this script attempt to create a"
|
|
# give auto-answer a chance to veto
|
|
if csih_request "new local group '${group}'?"
|
|
then
|
|
csih_call_winsys32 net localgroup "${group}" \
|
|
/add >/dev/null 2>&1 && grp_exists=yes
|
|
if [ "${grp_exists}" != "yes" ]
|
|
then
|
|
csih_warning "Creating the group '${group}' failed!"
|
|
else
|
|
# If we use /etc account DB only, write new group to /etc/group
|
|
if csih_use_file_etc group
|
|
then
|
|
/usr/bin/mkgroup -l -g "${group}" >> "${SYSCONFDIR}/group"
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ "${grp_exists}" = "yes" ]
|
|
then
|
|
local dw
|
|
|
|
map_entry="$(/usr/bin/getent -w group "U-${group}")"
|
|
csih_LOCAL_GROUPNAME="${map_entry%%:*}"
|
|
dw="${map_entry#*:*:}"
|
|
dw="${dw%:*}"
|
|
csih_LOCAL_GROUPDOMAIN="${dw%\\*}"
|
|
csih_LOCAL_GROUPWINNAME="${dw#*\\}"
|
|
return 0
|
|
fi
|
|
return 1
|
|
} # === End of csih_create_local_group() === #
|
|
readonly -f csih_create_local_group
|
|
|
|
# ======================================================================
|
|
# Routine: csih_service_should_run_as [service_name]
|
|
# If [service_name] is specified, check to see if service_name is
|
|
# already installed. If so, return that user (after verifying
|
|
# that it has the necessary privileges). If not installed, behave
|
|
# as described below.
|
|
# Should call csih_select_privileged_username first, unless SURE
|
|
# that [service_name] has already been installed.
|
|
#
|
|
# Otherwise:
|
|
#
|
|
# On 64bit Windows XP, Windows Server 2003 and above (including
|
|
# Windows Vista), or if csih_FORCE_PRIVILEGED_USER == "yes"
|
|
# returns the selected privileged account name, IF it exists (e.g.
|
|
# already existed, or was successfully created). Otherwise,
|
|
# returns "SYSTEM". Callers should check this and warn.
|
|
#
|
|
# On Windows NT/2k/XP32, if csih_FORCE_PRIVILEGED_USER != yes, then
|
|
# if a privileged user already exists, return it
|
|
# else return "SYSTEM"
|
|
#
|
|
# MUST call either csih_select_privileged_username
|
|
# or csih_create_privileged_user
|
|
# first.
|
|
# ======================================================================
|
|
csih_service_should_run_as()
|
|
{
|
|
csih_stacktrace "${@}"
|
|
$_csih_trace
|
|
local opt_servicename
|
|
local domain
|
|
local winusername
|
|
|
|
# caller specified a service, so first check to see if that service
|
|
# is already installed, and if so, analyze that account. (If not,
|
|
# fall thru...)
|
|
if [ -n "$1" ]
|
|
then
|
|
opt_servicename="$1"
|
|
if /usr/bin/cygrunsrv -Q "${opt_servicename}" >/dev/null 2>&1
|
|
then
|
|
username=$(/usr/bin/cygrunsrv -V -Q "${opt_servicename}" 2>&1 | /usr/bin/sed -n -e '/^Account/s/^.* : //p')
|
|
domain="${username/\\*/}"
|
|
winusername="${username/*\\/}"
|
|
if [ "${username}" = "LocalSystem" ]
|
|
then
|
|
username=SYSTEM
|
|
else
|
|
username=$(/usr/bin/getent passwd "${winusername}" "${domain}+${winusername}" | /usr/bin/head -n1 | /usr/bin/cut -d: -f 1)
|
|
fi
|
|
if ( csih_is_nt2003 || [ "x$csih_FORCE_PRIVILEGED_USER" = "xyes" ] )
|
|
then
|
|
if [ -n "${username}" -a "${username}" != SYSTEM ]
|
|
then
|
|
if csih_privileged_account_exists "${username}"
|
|
then
|
|
echo "${username}"
|
|
return
|
|
else
|
|
if csih_account_has_necessary_privileges "${username}"
|
|
then
|
|
echo "${username}"
|
|
return
|
|
else
|
|
csih_error_multi \
|
|
"${opt_servicename} is installed under custom account '${username}'," \
|
|
"but '${username}' does not have the necessary permissions or " \
|
|
"group membership. Please correct this problem before continuing." 1>&2
|
|
fi
|
|
fi
|
|
else
|
|
# two different error cases: -z $username, or $username=SYSTEM
|
|
if [ -z "${username}" ]
|
|
then
|
|
csih_error_multi \
|
|
"${opt_servicename} is installed, but there was a problem determining" \
|
|
"the user account under which it runs. Please correct this problem" \
|
|
"before continuing." 1>&2
|
|
else
|
|
csih_error_multi \
|
|
"${opt_servicename} is installed under account 'SYSTEM', but that" \
|
|
"conflicts with privileged user requirement. ${opt_servicename}" \
|
|
"must be installed under a special privileged account: either" \
|
|
"because the OS is 64bit Windows XP, Windows Server 2003, or above," \
|
|
"or you requested -privileged." 1>&2
|
|
fi
|
|
fi
|
|
else
|
|
# not nt2003|xp64 nor (nt && csih_FORCE_PRIVILEGED_USER=yes)
|
|
# we don't care about properties of $username...
|
|
if [ -z "${username}" ]
|
|
then
|
|
csih_error_multi \
|
|
"${opt_servicename} is installed, but there was a problem determining" \
|
|
"the user account under which it runs. Please correct this problem" \
|
|
"before continuing." 1>&2
|
|
else
|
|
echo "${username}"
|
|
return
|
|
fi
|
|
fi
|
|
fi # ${opt_servicename} not installed
|
|
fi # ${opt_servicename} not specified
|
|
|
|
# Caller did not specify a specific service, or the specified service
|
|
# is not yet installed, so compute the "expected" account under which
|
|
# privileged services should run.
|
|
|
|
# use the following procedure if a privileged account is required:
|
|
if ( csih_is_nt2003 || [ "x$csih_FORCE_PRIVILEGED_USER" = "xyes" ] )
|
|
then
|
|
if [ -z "${csih_PRIVILEGED_USERNAME}" ]
|
|
then
|
|
csih_warning "INTERNAL: should call 'csih_select_privileged_username()' before 'csih_service_should_run_as()'" 1>&2
|
|
fi
|
|
|
|
if csih_privileged_account_exists "$csih_PRIVILEGED_USERNAME" 1>&2
|
|
then
|
|
# it already existed before this script was launched
|
|
echo "$csih_PRIVILEGED_USERNAME"
|
|
return
|
|
elif /usr/bin/getent passwd "${csih_PRIVILEGED_USERNAME}" >/dev/null 2>&1
|
|
then
|
|
# we probably just created it
|
|
echo "$csih_PRIVILEGED_USERNAME"
|
|
return
|
|
else
|
|
# a failure somewhere
|
|
csih_warning "Expected privileged user '${csih_PRIVILEGED_USERNAME}' does not exist." 1>&2
|
|
csih_warning "Defaulting to 'SYSTEM'" 1>&2
|
|
echo "SYSTEM"
|
|
return
|
|
fi
|
|
fi
|
|
|
|
# not nt2003|xp64, and csih_FORCE_PRIVILEGED != yes).
|
|
# Use fallback: if any privileged user exists, report that. Otherwise,
|
|
# report SYSTEM
|
|
csih_privileged_accounts
|
|
if [ -n "${_csih_preferred_preexisting_privileged_account}" ]
|
|
then
|
|
echo "${_csih_preferred_preexisting_privileged_account}"
|
|
else
|
|
echo "SYSTEM"
|
|
fi
|
|
} # === End of csih_service_should_run_as() === #
|
|
readonly -f csih_service_should_run_as
|
|
|
|
# ======================================================================
|
|
# Routine: _csih_late_initialization_code
|
|
# Initializes variables that require complex script support, such
|
|
# as csih_invoke_helper.
|
|
#
|
|
# SETS GLOBAL VARIABLE:
|
|
# _csih_script_dir
|
|
# _csih_exec_dir
|
|
# _csih_exactly_vista
|
|
# _csih_exactly_server2008
|
|
# _csih_exactly_windows7
|
|
# _csih_exactly_server2008r2
|
|
# _csih_exactly_windows8
|
|
# _csih_exactly_server2012
|
|
# _csih_win_product_name
|
|
# ======================================================================
|
|
_csih_late_initialization_code()
|
|
{
|
|
local rstatus
|
|
local productName
|
|
|
|
# These two variables must be initialized before calling
|
|
# csih_invoke_helper
|
|
_csih_script_dir=$(_csih_get_script_dir)
|
|
_csih_exec_dir=$(_csih_get_exec_dir)
|
|
|
|
productName=$(csih_invoke_helper winProductName)
|
|
rstatus=$?
|
|
if [ "$rstatus" -eq 0 ]
|
|
then
|
|
if echo "${productName}" | /usr/bin/grep -q " Server 2016 "
|
|
then
|
|
_csih_exactly_server2016=1
|
|
elif echo "${productName}" | /usr/bin/grep -q " Windows 10 "
|
|
then
|
|
_csih_exactly_windows10=1
|
|
elif echo "${productName}" | /usr/bin/grep -q " Server 2012 R2 "
|
|
then
|
|
_csih_exactly_server2012r2=1
|
|
elif echo "${productName}" | /usr/bin/grep -q " Windows 8\.1 "
|
|
then
|
|
_csih_exactly_windows8_1=1
|
|
elif echo "${productName}" | /usr/bin/grep -q " Server 2012 "
|
|
then
|
|
_csih_exactly_server2012=1
|
|
elif echo "${productName}" | /usr/bin/grep -q " Windows 8 "
|
|
then
|
|
_csih_exactly_windows8=1
|
|
elif echo "${productName}" | /usr/bin/grep -q " Server 2008 R2 "
|
|
then
|
|
_csih_exactly_server2008r2=1
|
|
elif echo "${productName}" | /usr/bin/grep -q " Windows 7 "
|
|
then
|
|
_csih_exactly_windows7=1
|
|
elif echo "${productName}" | /usr/bin/grep -q " Server 2008 "
|
|
then
|
|
_csih_exactly_server2008=1
|
|
elif echo "${productName}" | /usr/bin/grep -q " Vista "
|
|
then
|
|
_csih_exactly_vista=1
|
|
fi
|
|
_csih_win_product_name="${productName}";
|
|
fi
|
|
} # === End of _csih_late_initialization_code() === #
|
|
readonly -f _csih_late_initialization_code
|
|
|
|
|
|
# ======================================================================
|
|
# Initial setup, default values, etc. PART 3
|
|
#
|
|
# This part of the setup has to be deferred to the end of the csih
|
|
# script, since we need many of the previously defined functions to
|
|
# be available (such as csih_invoke_helper) before the variable values
|
|
# can be obtained. Most of this initialization is encapsulated in the
|
|
# _csih_late_initialization_code() function.
|
|
#
|
|
# Finally, we ensure that this file is being used properly (that is,
|
|
# sourced by another script rather than executed directly), and that
|
|
# the current cygwin and Windows versions are supported. csih requires
|
|
# WinNT or above and cygwin-1.7.x or above.
|
|
# ======================================================================
|
|
_csih_late_initialization_code
|
|
readonly _csih_script_dir _csih_exec_dir
|
|
readonly _csih_exactly_vista _csih_exactly_server2008
|
|
readonly _csih_exactly_server2008r2 _csih_exactly_windows7
|
|
readonly _csih_exactly_server2012 _csih_exactly_windows8
|
|
readonly _csih_exactly_server2012r2 _csih_exactly_windows8_1
|
|
readonly _csih_exactly_server2016 _csih_exactly_windows10
|
|
readonly _csih_win_product_name
|
|
|
|
if [ "cygwin-service-installation-helper.sh" = "$csih_progname_base" ]
|
|
then
|
|
csih_error "$csih_progname_base should not be executed directly"
|
|
fi
|