the-bastion/lib/shell/functions.inc
Stéphane Lesimple 70feff2c2d enh: install: use in-place overwrite for sudoers files
This fixes a race condition in sudo where it would log a log of
error messages to syslog if used while we're running the install
script: files around sudoers.d/ are then moved around, and it'll
yell for each file it previously listed if the file no longer
exists when it tries to stat() it. It also deprecates the --no-wait
flag of the install script, as now the sudoers.d/ directory will
always have integrity at all times.

Signed-off-by: Stéphane Lesimple <stephane.lesimple+bastion@ovhcloud.com>
2021-02-14 22:25:50 +01:00

337 lines
9.3 KiB
Bash

# vim: set filetype=sh ts=4 sw=4 sts=4 et:
# shellcheck shell=bash
# shellcheck source=lib/shell/colors.inc disable=SC2128
. "$(dirname "$BASH_SOURCE")"/colors.inc
# authorized_keys file, relative to the user's HOME directory.
# if you change this, also change it in lib/perl/OVH/Bastion.pm
# shellcheck disable=SC2034
AK_FILE=".ssh/authorized_keys2"
OS_FAMILY=$(uname -s)
LINUX_DISTRO=unknown
DISTRO_VERSION=''
DISTRO_LIKE=''
if [ -e /etc/os-release ]; then
LINUX_DISTRO=$(grep '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"')
DISTRO_LIKE=$(grep '^ID_LIKE=' /etc/os-release | cut -d= -f2 | tr -d '"')
DISTRO_VERSION=$(grep '^VERSION_ID=' /etc/os-release | cut -d= -f2 | tr -d '"')
fi
if [ -z "$LINUX_DISTRO" ] || [ -z "$DISTRO_VERSION" ]; then
if command -v lsb_release >/dev/null 2>&1; then
LINUX_DISTRO=$(lsb_release -si)
DISTRO_VERSION=$(lsb_release -sr)
elif [ -e /etc/debian_version ]; then
LINUX_DISTRO=debian
DISTRO_VERSION=$(cat /etc/debian_version)
elif [ -e /etc/redhat-release ]; then
LINUX_DISTRO=redhat
fi
fi
if [ "$DISTRO_VERSION" = "buster/sid" ]; then
DISTRO_VERSION=10
fi
LINUX_DISTRO=$(echo "$LINUX_DISTRO" | tr '[:upper:]' '[:lower:]' | tr -d ' ')
# shellcheck disable=SC2034
DISTRO_VERSION_MAJOR=$(echo "$DISTRO_VERSION" | grep -Eo '^[0-9]+' || true)
[ -z "$DISTRO_LIKE" ] && DISTRO_LIKE="$LINUX_DISTRO"
# no longer needed, but keep if for a few versions so that non-restarted daemons are still happy
# shellcheck disable=SC2034
LOCKFILE=/var/run/bastion-upgrade.lock
# set ETC_DIR
ETC_DIR=/etc
[ "$OS_FAMILY" = FreeBSD ] && ETC_DIR=/usr/local/etc
[ "$OS_FAMILY" = NetBSD ] && ETC_DIR=/usr/pkg/etc
# shellcheck disable=SC2034
BASTION_ETC_DIR=$ETC_DIR/bastion
# set UID0 and GID0 (os-dependent)
# shellcheck disable=SC2034
UID0=$(getent passwd 0 | awk -F: '{print $1}')
# shellcheck disable=SC2034
GID0=$(getent group 0 | awk -F: '{print $1}')
# shellcheck disable=SC2034
UID0HOME=$(getent passwd 0 | awk -F: '{print $6}')
# set sudoers_dir
SUDOERS_FILE=/etc
if [ -e /usr/local/etc/sudoers ] && ! [ -e /etc/sudoers ] ; then
SUDOERS_FILE=/usr/local/etc
elif [ -e /usr/pkg/etc/sudoers ] && ! [ -e /etc/sudoers ] ; then
SUDOERS_FILE=/usr/pkg/etc
fi
# shellcheck disable=SC2034
SUDOERS_DIR="$SUDOERS_FILE/sudoers.d"
SUDOERS_FILE="$SUDOERS_FILE/sudoers"
# set SSH_DIR
SSH_DIR=$ETC_DIR/ssh
if [ ! -e "$SSH_DIR" ]; then
SSH_DIR=/etc/ssh
fi
# set PAM_DIR
PAM_DIR=$ETC_DIR/pam.d
if [ ! -e "$PAM_DIR" ]; then
PAM_DIR=/etc/pam.d
fi
# set PAM_SSHD
# under FreeBSD, both /usr/local/etc/pam.d and /etc/pam.d can exist
PAM_SSHD="/etc/pam.d/sshd"
if [ -e "/usr/local/etc/pam.d/sshd" ]; then
# shellcheck disable=SC2034
PAM_SSHD="/usr/local/etc/pam.d/sshd"
fi
# set CRON_DIR
CRON_DIR=$ETC_DIR/cron.d
if [ ! -e "$CRON_DIR" ]; then
CRON_DIR=/etc/cron.d
fi
action_doing()
{
printf '\r*** %b\n' "$*"
}
action_detail()
{
printf '\r`-> %b\n' "$*"
}
action_done()
{
printf "%b" "\\r\`-> [${GREEN} OK ${NOC}]"
if [ -n "$1" ]; then
printf "%b" " ... $*"
fi
echo
}
action_warn()
{
printf '%b %b\n' "\\r\`-> [${YELLOW}WARN${NOC}]" "$*"
}
action_error()
{
printf '%b %b\n' "\\r\`-> [${RED}ERR.${NOC}]" "$*"
}
action_na()
{
printf '%b %b\n' "\\r\`-> [${BLUE}N/A.${NOC}]" "$*"
}
sed_compat()
{
local _sedcmd="$1" _file="$2"
if sed --version 2>/dev/null | grep -q GNU || [ "$OS_FAMILY" = NetBSD ] ; then
# GNU sed or NetBSD
sed -i -re "$_sedcmd" "$_file"
else
# other BSD-style sed
sed -i '' -re "$_sedcmd" "$_file"
fi
}
md5sum_compat()
{
if command -v gmd5sum >/dev/null; then
gmd5sum "$@"; return $?
else
md5sum "$@"; return $?
fi
}
useradd_compat()
{
local _user="$1" _uid="" _home="" _shell="" _gid="" _extra=""
shift
if [ -n "$*" ]; then _uid="$1"; shift; fi
if [ -n "$*" ]; then _home="$1"; shift; fi
if [ -n "$*" ]; then _shell="$1"; shift; fi
if [ -n "$*" ]; then _gid="$1"; shift; fi
[ -n "$_uid" ] && _extra="$_extra -u $_uid"
if [ -n "$_home" ]; then
_extra="$_extra -d $_home"
fi
if [ "$_home" != "/nonexistent" ]; then
_extra="$_extra -m"
fi
if [ -n "$_gid" ]; then
_extra="$_extra -g $_gid"
elif command -v useradd >/dev/null ; then
[ "$OS_FAMILY" != OpenBSD ] && [ "$OS_FAMILY" != NetBSD ] && _extra="$_extra -U"
fi
# special case for /bin/false, it might be /usr/bin/false on some BSDs
if [ "$_shell" = /bin/false ] && ! [ -e /bin/false ] && [ -e /usr/bin/false ] ; then
_shell="/usr/bin/false"
fi
[ -n "$_shell" ] && _extra="$_extra -s $_shell"
if command -v useradd >/dev/null ; then
if [ "$OS_FAMILY" = OpenBSD ] || [ "$OS_FAMILY" = NetBSD ]; then
# shellcheck disable=SC2086
useradd -r 400..499 -g =uid $_extra "$_user"
else
# shellcheck disable=SC2086
useradd -r -p '*' $_extra "$_user"
fi
elif command -v pw >/dev/null ; then
# shellcheck disable=SC2086
pw useradd -n "$_user" $_extra
else
echo "useradd_compat: Don't know how to add user $_user!" >&2
return 1
fi
}
groupadd_compat()
{
local _group="$1" _gid="$2"
if command -v groupadd >/dev/null ; then
if [ -n "$_gid" ] && [ "$_gid" != HIGH ]; then
# works for Linux, NetBSD and OpenBSD
groupadd -g "$_gid" "$_group"
elif [ "$OS_FAMILY" = Linux ] ; then
if [ "$_gid" = HIGH ]; then
groupadd "$_group"
else
groupadd -r "$_group"
fi
elif [ "$OS_FAMILY" = NetBSD ]; then
if [ "$_gid" = HIGH ]; then
groupadd "$_group"
else
groupadd -r 300..399 "$_group"
fi
elif [ "$OS_FAMILY" = OpenBSD ]; then
if [ -z "$_gid" ] ; then
# try to pick a groupid ourselves...
local _g=0
for _g in {300..399} ; do
if ! groupinfo -e "$_g" ; then
groupadd -g "$_g" "$_group"
return 0
fi
done
fi
# couldn't find any (or highid asked)... let the system decide
groupadd "$_group"
else
groupadd "$_group"
fi
elif command -v pw >/dev/null ; then
if [ -n "$_gid" ] && [ "$_gid" != HIGH ]; then
pw groupadd -n "$_group" -g "$_gid"
return 0
elif [ -z "$_gid" ] ; then
# try to pick a groupid ourselves...
local _g=0
for _g in {300..399} ; do
if ! pw groupshow -g "$_g" &>/dev/null ; then
pw groupadd -g "$_g" -n "$_group"
return 0
fi
done
fi
# couldn't find any (or highid asked)... let the system decide
pw groupadd -n "$_group"
else
echo "groupadd_compat: Don't know how to add group $_group!" >&2
return 1
fi
}
usermod_changeuid_compat()
{
local _user="$1" _newuid="$2"
if command -v usermod >/dev/null ; then
usermod -u "$_newuid" "$_user"
elif command -v pw >/dev/null ; then
pw usermod -n "$_user" -u "$_newuid"
else
echo "usermod_changeuid_compat: Don't know how to change uid of user $_user to $_newuid!" >&2
return 1
fi
}
group_change_gid_compat()
{
local _group="$1" _newgid="$2"
if command -v groupmod >/dev/null ; then
groupmod -g "$_newgid" "$_group"; return $?
elif command -v pw >/dev/null ; then
pw groupmod -n "$_group" -g "$_newgid"; return $?
else
echo "group_change_gid_compat: Don't know how to change gid of group $_group to $_newgid!" >&2
return 1
fi
}
group_rename_compat()
{
local _oldname="$1" _newname="$2"
if command -v groupmod >/dev/null ; then
groupmod -n "$_newname" "$_oldname"; return $?
elif command -v pw >/dev/null ; then
pw groupmod -n "$_oldname" -l "$_newname"; return $?
else
echo "group_rename_compat: Don't know how to rename group $_oldname to $_newname!" >&2
return 1
fi
}
add_user_to_group_compat()
{
local _user="$1" _group="$2"
if command -v usermod >/dev/null ; then
if [ "$OS_FAMILY" = OpenBSD ] || [ "$OS_FAMILY" = NetBSD ] ; then
usermod -G "$_group" "$_user"
else
usermod -a -G "$_group" "$_user"
fi
elif command -v pw >/dev/null ; then
pw groupmod -n "$_group" -m "$_user"
else
echo "add_user_to_group_compat: don't know how to add $_user to $_group!" >&2
return 1
fi
}
del_user_from_group_compat()
{
local _user="$1" _group="$2"
if command -v gpasswd >/dev/null ; then
gpasswd -d "$_user" "$_group"
elif command -v pw >/dev/null ; then
pw groupmod -n "$_group" -d "$_user"
else
echo "del_user_from_group_compat: don't know how to del $_user from $_group!" >&2
return 1
fi
}
_logtag="$(basename "$0")[$$]"
__log()
{
level="$1"
shift
[ -n "$LOG_FACILITY" ] && logger -t "$_logtag" -p "$LOG_FACILITY"."$level" "$*"
[ -z "$LOG_QUIET" ] && echo "$(date +'[%Y/%m/%d %H:%M:%S] ')$*"
}
_log()
{
__log info "$*"
}
_warn()
{
__log warn "WARN: $*"
}
_err()
{
__log err "ERROR: $*" >&2
}