This repository has been archived on 2020-07-29. You can view files and clone it, but cannot push or open issues or pull requests.
jailspaces/js

1347 lines
44 KiB
Text
Raw Normal View History

2016-05-06 18:58:56 +02:00
#!/bin/bash
_CONF_FILE="/etc/jailspaces/js.conf"
check_config() {
[ -f "$_PHP_FPM_CONF_TEMPLATE" ] || die "$_PHP_FPM_CONF_TEMPLATE missing"
[ -f "$_NGINX_CONF_TEMPLATE" ] || die "$_NGINX_CONF_TEMPLATE missing"
# TODO:
}
get_user_list() {
eval "$_USER_LIST_CMD" | while read user; do echo $user; done;
}
user_create() {
local cmd="${_USER_CREATE_CMD//@USERNAME@/$1}"
eval "$cmd"
return $?
}
user_exists() {
get_user_list | grep -x "$1" &> /dev/null
return $?
}
group_exists() {
getent group | grep -P "^$1:" &> /dev/null
return $?
}
user_is_valid() {
echo "$1" | grep -ivP "[^a-z0-9]" &> /dev/null && [ "`echo -n \"$1\" | wc -c`" -le 10 ] && [ "`echo -n \"$1\" | wc -c`" -ge 4 ] && return 0
return 1
}
get_user_chroot() {
echo "${_PHP_FPM_CHROOT//@USERNAME@/$1}"
}
get_user_binds() {
local username="$1"
echo $_PHP_FPM_CHROOT_BIND
if [ -n "$username" ]; then
local bind_local="${_PHP_FPM_CHROOT_BIND_LOCAL//@USERNAME@/$username}"
[ -f "$bind_local" ] && cat "$bind_local"
fi
}
die() {
echo "ERROR: $1" && stop 1
}
is_valid_fqdn() {
echo "$1" | grep -P '^(?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63}$' &> /dev/null
return $?
}
get_FQDNs_for_user() {
local nginx_config="${_NGINX_CONF//@USERNAME@/$1}"
[ ! -r "$nginx_config" ] && nginx_config="$nginx_config.disabled"
[ -r "$nginx_config" ] || echo ""
for domain in `grep -P '^\s*server_name\s+.+;$' "$nginx_config" | rev | cut -c 2- | rev`; do
[ "$domain" = "server_name" ] && continue;
is_valid_fqdn "$domain" && echo "$domain"
done | sort -u;
}
file_has() {
case "$1" in
perm) [ -e "$2" -a "`printf '%04d' \`stat -c '%a' $2\``" = "$3" ] && return 0 || return 1;;
owner) [ -e "$2" -a "`stat -c '%U:%G' $2`" = "$3" ] && return 0 || return 1;;
type) [ "$3" = "f" -a -f "$2" ] && return 0; [ "$3" = "d" -a -d "$2" ] && return 0; return 1;;
esac
}
color() {
local n="\033[0m"
local g="\033[32m"
local y="\033[33m"
local r="\033[31m"
eval "echo -en \"\$$1\""
echo -e "$2$n"
}
status() {
local msg="";
case "$1" in
g) msg="$2";;
y) msg="$3";;
r) msg="$4";;
esac
[ -n "$msg" ] && echo -n "[`color $1 \"$msg\"`]"
}
check_file_permissions() {
local uUSERNAME="$1"
local uCHROOT="`get_user_chroot $uUSERNAME`"
local violation=false
local cfile=""
local suffix=""
local f=1
for permDef in $_PHP_FPM_CHROOT_DIRS; do
f=1; for field in file perm owner type; do eval "f_$field=\"`echo $permDef | cut -d, -f$f`\""; f=$(($f+1)); done;
f_file="${f_file//@USERNAME@/$uUSERNAME}"
cfile=$uCHROOT$f_file
suffix="$f_perm,${f_owner//@USERNAME@/$uUSERNAME},$f_type"
echo -n "$f_file,"
[ ! -e "$cfile" ] && violation=true && echo "false,true,true,true,$suffix" && continue;
! file_has perm "$cfile" "$f_perm" && violation=true && echo -n "true,false," || echo -n "true,true,"
! file_has owner "$cfile" "${f_owner//@USERNAME@/$uUSERNAME}" && violation=true && echo -n "false," || echo -n "true,"
! file_has type "$cfile" "$f_type" && violation=true && echo -n "false," || echo -n "true,"
echo "$suffix"
done;
$violation && return 1 || return 0
}
fix_or_check_file_permissions() {
local uUSERNAME="$1"
local uCHROOT="`get_user_chroot $uUSERNAME`"
local fix=false
local f=1
local returnValue=0
[ -n "$2" ] && fix=true
check_file_permissions "$uUSERNAME" | while read check; do
f=1; for field in file exists perm owner type iperm iowner itype; do eval "f_$field=\"`echo $check | cut -d, -f$f`\""; f=$(($f+1)); done;
local fullPath="$uCHROOT$f_file"
if ! $f_exists; then
local msg="$f_file does not exist"
if $fix; then
local status="r"
[ "$f_itype" = "f" ] && touch "$fullPath" &> /dev/null && [ -f "$fullPath" ] && status="g"
[ "$f_itype" = "d" ] && status="r" && mkdir -p "$fullPath" &> /dev/null && [ -d "$fullPath" ] && status="g"
[ "$status" = "g" ] && status="r" && chown "$f_iowner" "$fullPath" && chmod "$f_iperm" "$fullPath" && status="g"
printf "$pf2" "$msg" "`status $status 'CREATED' '' 'FAILED'`"
[ "$status" = "g" ] || returnValue=1
else
printf "$pf1" "" "$msg"
fi
fi
if ! $f_perm; then
local msg="$f_file has wrong permissions (must $f_iperm)"
if $fix; then
local status='r'
chmod "$f_iperm" "$fullPath" && status="g"
printf "$pf2" "$msg" "`status $status 'FIXED' '' 'FAILED'`"
[ "$status" = "g" ] || returnValue=1
else
printf "$pf1" "" "$msg"
fi
fi
if ! $f_owner; then
local msg="$f_file has wrong ownership (must $f_iowner)"
if $fix; then
local status="r"
chown "$f_iowner" "$fullPath" && status="g"
printf "$pf2" "$msg" "`status $status 'FIXED' '' 'FAILED'`"
[ "$status" = "g" ] || returnValue=1
else
printf "$pf1" "" "$msg"
fi
fi
if ! $f_type; then
local msg=""
[ -f "$fullPath" ] && msg="$f_file is not a directory"
[ -d "$fullPath" ] && msg="$f_file is not a regular file"
if $fix; then
printf "$pf2" "$msg --> please fix manually" "`status y '' 'SKIPPED'`"
else
printf "$pf1" "" "$msg"
fi
fi
done;
return $returnValue
}
# template destination owner mode var1 value1 var2 value2
install_template() {
local template="$1"
local destination="$2"
local owner="$3"
local mode="$4"
shift 4
[ ! -f "$template" ] && printf "$pf2" "Template \"$template\" does not exist" "`status r '' '' 'ERROR'`" && return 1
[ -f "$destination" -o -f "$destination.disabled" ] && printf "$pf2" "Template target \"$destination\" already in use" "`status r '' '' 'ERROR'`" && return 2
local sedCmd="sed"
while [ $# -gt 0 ]; do
sedCmd="$sedCmd -e \"s/@$1@/$2/g\""
shift 2
done
sedCmd="$sedCmd \"$template\""
local returnValue=0
local status="r"
eval "$sedCmd" > "$destination" && status="g"
printf "$pf2" "Installing template to \"$destination\"" "`status $status 'DONE' '' 'FAILED'`"
[ "$status" = "g" ] || return 1
[ "$status" = "g" ] && status="r" && chown "$owner" "$destination" && status="g"
printf "$pf2" "Setting ownership to $owner" "`status $status 'DONE' '' 'FAILED'`"
[ "$status" = "g" ] || returnValue=1
[ "$status" = "g" ] && status="r" && chmod "$mode" "$destination" && status="g"
printf "$pf2" "Setting mode to $mode" "`status $status 'DONE' '' 'FAILED'`"
[ "$status" = "g" ] || returnValue=1
return $returnValue
}
is_bound() {
mount | grep " on $1 type " > /dev/null && return 0 || return 1
}
get_base_path() {
local path="$1"
local lastPath=""
while [ "$path" != "/" ]; do lastPath=$path; path=`dirname $path`; done;
echo "$lastPath"
}
is_any_unbound() {
local username="$1"
local chroot="`get_user_chroot \"$username\"`"
for bind in `get_user_binds "$username"`; do
is_bound "$chroot$bind" || return 0
done
return 1
}
is_any_bound() {
local username="$1"
local chroot="`get_user_chroot \"$username\"`"
for bind in `get_user_binds "$username"`; do
is_bound "$chroot$bind" && return 0
done
return 1
}
reload_services() {
local status="r"
local error=false
local sudo=""
[ -n "$2" -a "$2" = "sudo" ] && sudo="sudo "
if [ -n "$_OPT_RELOAD" ] && $_OPT_RELOAD; then
if [ -z "$1" -o "$1" = "nginx" -o "$1" = "ALL" ]; then
eval "$sudo$_RELOAD_NGINX_CMD" && status="g"
printf "$pf2" "Reloading NGINX" "`status $status 'DONE' '' 'FAILED'`"
[ "$status" = "g" ] || error=true
fi
if [ -z "$1" -o "$1" = "php-fpm" -o "$1" = "ALL" ]; then
status="r"
eval "$sudo$_RELOAD_PHP_FPM_CMD" && status="g"
printf "$pf2" "Reloading PHP-FPM" "`status $status 'DONE' '' 'FAILED'`"
[ "$status" = "g" ] || error=true
fi
fi
if $error; then
return 1
else
return 0
fi
}
reset_nscd() {
nscd --invalidate passwd &> /dev/null
nscd --invalidate group &> /dev/null
}
stop() {
rm -f "$_LOCKFILE"
exit $1
}
le_cmd() {
if $_LOW_PRIV_TLS_REFRESH; then
eval "$1"
else
su -c "$1" "$_LETS_ENCRYPT_USER"
fi
return $?
}
cert_get_domains() {
local commonName="`openssl x509 -noout -text -in \"$1\" | grep 'Subject: CN=' | cut -d= -f2`"
[ -n "$commonName" ] && echo $commonName
# Subject Alternative Names
[ -z "`openssl x509 -noout -text -in \"$1\" | grep 'X509v3 Subject Alternative Name:'`" ] && return 0
for d in \
`openssl x509 -noout -text -in "$1" | \
grep -A1 'X509v3 Subject Alternative Name:' \
| tail -n1 | tr -d '[:space:]' | \
sed -e 's/DNS://g' -e 's/,/ /g'`; do
[ "$d" != "$commonName" ] && echo $d; done;
}
cert_get_expiry() {
local expiry="`openssl x509 -noout -text -in \"$1\" | grep 'Not After' | cut -d: -f2-4`";
date -d "$expiry" +%s
}
create_systemd_units() {
[ ! -f "${_SYSTEMD_UNIT_DIR}/rebindreadonly@.service" ] && \
cat <<- END > "${_SYSTEMD_UNIT_DIR}/rebindreadonly@.service" && \
echo -e "Created ${_SYSTEMD_UNIT_DIR}/rebindreadonly@.service"
# PHP-FPM-CHROOT-BIND
[Unit]
Description=Remount bind for PHP-FPM chroot readonly
DefaultDependencies=no
After=%i.mount
Before=local-fs.target
[Service]
Type=oneshot
ExecStart=/bin/mount -o remount,bind,ro /%I
END
local chroot=""
local eChroot=""
local bind=""
local eBind=""
local mountpoint=""
[ ! -f "${_SYSTEMD_UNIT_DIR}/php-chroots.target" ] && \
cat <<- END > "${_SYSTEMD_UNIT_DIR}/php-chroots.target" && \
echo -e "Created ${_SYSTEMD_UNIT_DIR}/php-chroots.target"
# PHP-FPM-CHROOT-BIND
[Install]
WantedBy=php5-fpm.service
[Unit]
Description=Bind all binds for all PHP-FPM chroots
Before=php5-fpm.service
END
get_user_list | while read user; do
chroot="`get_user_chroot ${user}`"
eChroot="`systemd-escape -p \"${chroot}\"`"
[ ! -f "${_SYSTEMD_UNIT_DIR}/php-chroot-${eChroot}.target" ] && \
cat <<- END > "${_SYSTEMD_UNIT_DIR}/php-chroot-${eChroot}.target" && \
echo -e "Created ${_SYSTEMD_UNIT_DIR}/php-chroot-${eChroot}.target"
# PHP-FPM-CHROOT-BIND
[Unit]
Description=Bind all binds for PHP-FPM chroot ${chroot}
END
for bind in `get_user_binds "$user"`; do
eBind="`systemd-escape -p \"${bind}\"`"
mountpoint="`systemd-escape -p \"${chroot}${bind}\"`"
[ ! -f "${_SYSTEMD_UNIT_DIR}/${mountpoint}.mount" ] && \
cat <<- END > "${_SYSTEMD_UNIT_DIR}/${mountpoint}.mount" && \
echo -e "Created ${_SYSTEMD_UNIT_DIR}/${mountpoint}.mount"
# PHP-FPM-CHROOT-BIND
[Unit]
Description=Bind ${bind} for PHP-FPM chroot ${chroot}
Requires=rebindreadonly@${mountpoint}.service
Requires=php-chroot-create-mountpoint-file-${eBind}@${eChroot}.service
Requires=php-chroot-create-mountpoint-dir-${eBind}@${eChroot}.service
BindsTo=php-chroot-${eChroot}.target
[Mount]
What=${bind}
Where=${chroot}${bind}
Type=none
Options=bind
END
[ ! -f "${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-file-${eBind}@.service" ] && \
cat <<- END > "${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-file-${eBind}@.service" && \
echo -e "Created ${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-file-${eBind}@.service"
# PHP-FPM-CHROOT-BIND
[Unit]
Description=Create mountpoint (file) for ${bind} in PHP-FPM Chroot
Before=%i-${eBind}.mount
ConditionPathExists=!/%I${bind}
ConditionPathExists=${bind}
ConditionPathIsDirectory=!${bind}
[Service]
Type=oneshot
ExecStart=/bin/mkdir -p "/%I${bind}" ; /bin/rm -r "/%I${bind}" ; /usr/bin/touch "/%I${bind}"
END
[ ! -f "${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-dir-${eBind}@.service" ] && \
cat <<- END > "${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-dir-${eBind}@.service" && \
echo -e "Created ${_SYSTEMD_UNIT_DIR}/php-chroot-create-mountpoint-dir-${eBind}@.service"
# PHP-FPM-CHROOT-BIND
[Unit]
Description=Create mountpoint (dir) for ${bind} in PHP-FPM Chroot
Before=%i-${eBind}.mount
ConditionPathExists=!/%I${bind}
ConditionPathExists=${bind}
ConditionPathIsDirectory=${bind}
[Service]
Type=oneshot
ExecStart=/bin/mkdir -p "/%I${bind}"
END
echo "Requires=${mountpoint}.mount" >> "${_SYSTEMD_UNIT_DIR}/php-chroot-${eChroot}.target"
done
echo "BindsTo=php-chroots.target" >> "${_SYSTEMD_UNIT_DIR}/php-chroot-${eChroot}.target"
echo "Wants=php-chroot-${eChroot}.target" >> "${_SYSTEMD_UNIT_DIR}/php-chroots.target"
done
return 0
}
list_systemd_units() {
local unit=""
ls -1b "${_SYSTEMD_UNIT_DIR}/"* 2> /dev/null | while read unit; do
[ -f "$unit" ] && head -n1 "${unit}" | \
grep -x "# PHP-FPM-CHROOT-BIND" > /dev/null && echo "${unit}"
done
return 0
}
delete_systemd_units() {
ls -1b "${_SYSTEMD_UNIT_DIR}/"* 2> /dev/null | while read unit; do
[ -f "$unit" ] && head -n1 "${unit}" | \
grep -x "# PHP-FPM-CHROOT-BIND" > /dev/null && \
echo -n "${unit}" && if $_OPT_YES; then
rm "${unit}" && echo " (deleted)"
else
echo " (not deleted, use -Y)"
fi
done
return 0
}
pf0="%-16s: %-50s %11s\n"
pf1="%-18s%s\n"
pf2="%-69s%11s\n"
! source "$_CONF_FILE" &> /dev/null && printf "$pf2" "$_CONF_FILE could not be read." "`status r '' '' 'ERROR'`" && stop 1
# Skip single instance check for internal calls
_OPT_INTERNAL_CALL=false
if [ "$1" = "_INTERNAL_" -a "$EUID" -eq 0 ]; then
_OPT_INTERNAL_CALL=true
shift
fi
case "$1" in
list)
_OPT_ACTION="list"
;;
status|fixperm)
_OPT_ACTION="$1"
_OPT_USERNAME="$2"
;;
enable|disable)
_OPT_ACTION="$1"
_OPT_USERNAME="$2"
_OPT_RELOAD=true
if [ -n "$3" ]; then
[ "$3" != "-n" ] && _OPT_ACTION="help"
_OPT_RELOAD=false
fi
;;
binds)
_OPT_ACTION="binds"
_OPT_USERNAME="$3"
case "$2" in
bind ) _OPT_ACTION_BIND="bind";;
unbind) _OPT_ACTION_BIND="unbind";;
clean )
_OPT_ACTION_BIND="clean"
_OPT_YES=false
[ -n "$4" -a "$4" = "-Y" ] && _OPT_YES=true
;;
status) _OPT_ACTION_BIND="status";;
list ) _OPT_ACTION_BIND="list";;
systemd)
_OPT_ACTION_BIND="systemd"
case "$3" in
list) _OPT_ACTION_BIND_SYSTEMD="list";;
create) _OPT_ACTION_BIND_SYSTEMD="create";;
clean)
_OPT_ACTION_BIND_SYSTEMD="clean"
_OPT_YES=false
[ -n "$4" -a "$4" = "-Y" ] && _OPT_YES=true
;;
update) _OPT_ACTION_BIND_SYSTEMD="update";;
*)_OPT_ACTION="help";;
esac;;
*)_OPT_ACTION="help";;
esac
;;
create)
_OPT_ACTION="create"
_OPT_USERNAME="$2"
_OPT_DOMAINS=""
shift 2
while [ "$#" -gt 0 ]; do
! is_valid_fqdn "$1" && printf "$pf2" "$1 is not a valid FQDN" "`status r '' '' 'ERROR'`" && stop 1
_OPT_DOMAINS="$_OPT_DOMAINS $1"
shift
done
;;
delete)
_OPT_ACTION="delete"
_OPT_USERNAME="$2"
_OPT_YES=false
[ -n "$3" -a "$3" = "-Y" ] && _OPT_YES=true
;;
tls)
_OPT_ACTION="tls"
case "$2" in
init) _OPT_ACTION_TLS="init";;
refresh|forcerefresh)
_OPT_ACTION_TLS="refresh"
_OPT_ACTION_TLS_FORCEREFRESH=false
[ "$2" = "forcerefresh" ] && _OPT_ACTION_TLS_FORCEREFRESH=true
_OPT_USERNAME="$3"
_OPT_RELOAD=true
if [ -n "$4" ]; then
[ "$4" != "-n" ] && _OPT_ACTION="help"
_OPT_RELOAD=false
fi
;;
*) _OPT_ACTION="help";;
esac
;;
*)
_OPT_ACTION="help"
;;
esac
# Check if this is the only instance
if ! $_OPT_INTERNAL_CALL; then
_LOCKFILE="/tmp/wss.lock"
if [ -e "$_LOCKFILE" ] && kill -0 `cat $_LOCKFILE` &> /dev/null; then
printf "$pf2" "Another instance of this script seems to be runnig" "`status r '' '' 'ERROR'`"
exit 1
fi
trap "rm -f $_LOCKFILE;" INT TERM EXIT
echo $$ > $_LOCKFILE
fi
# Check if we run as letsencrypt user for certificate refresh
_LOW_PRIV_TLS_REFRESH=false
if [ "$USER" = "$_LETS_ENCRYPT_USER" -a "$_OPT_ACTION_TLS" = "refresh" ]; then
_LOW_PRIV_TLS_REFRESH=true
fi
# Check if this is run as root
if ! $_LOW_PRIV_TLS_REFRESH && [ "$EUID" -ne 0 ]; then
printf "$pf2" "Not run as root" "`status r '' '' 'ERROR'`"
stop 1
fi
if ! echo "$_OPT_ACTION" | grep -P "list|help" &> /dev/null && [ "$_OPT_ACTION_TLS" != "init" ] && [ "$_OPT_ACTION_BIND" != "systemd" ]; then
if ! user_is_valid "$_OPT_USERNAME" ]; then
printf "$pf2" "Username \"$_OPT_USERNAME\" is not valid" "`status r '' '' 'ERROR'`"
stop 1
fi
fi
if ! echo "$_OPT_ACTION" | grep -P "list|help|create" &> /dev/null && [ "$_OPT_ACTION_TLS" != "init" ] && [ "$_OPT_ACTION_BIND" != "systemd" ]; then
if ! user_exists "$_OPT_USERNAME"; then
printf "$pf2" "Username \"$_OPT_USERNAME\" does not exist" "`status r '' '' 'ERROR'`"
stop 1
fi
fi
uUSERNAME="$_OPT_USERNAME"
uCERT="$_LETS_ENCRYPT_CRT_DIR/$uUSERNAME.crt"
uCHROOT="`get_user_chroot \"$uUSERNAME\"`"
uPOOL="${_PHP_FPM_CONF//@USERNAME@/$uUSERNAME}"
uNGINX="${_NGINX_CONF//@USERNAME@/$uUSERNAME}"
id "$uUSERNAME" &> /dev/null && status_user_exists="g" || status_user_exists="r"
[ -r "$uNGINX" ] && status_nginx_exists="g" || status_nginx_exists="r" && [ -r "$uNGINX.disabled" ] && status_nginx_exists="y"
[ "$status_nginx_exists" != "r" ] && uFQDNS="`get_FQDNs_for_user \"$uUSERNAME\"`"
status_crt_exists="g"
status_crt_expiry="g"
status_crt_fqdns="g"
if $_LETS_ENCRYPT_ENABLE; then
[ -e "$uCERT" ] && status_crt_exists="g" || status_crt_exists="r"
if [ "$status_crt_exists" = "g" ]; then
uCERTFQDNS="`cert_get_domains \"$uCERT\"`"
timeToExpiry=$((`cert_get_expiry "$uCERT"`-`date +%s`))
[ "$timeToExpiry" -le "$_LETS_ENCRYPT_EXPIRY" ] && status_crt_expiry="y"
[ "$timeToExpiry" -le 0 ] && status_crt_expiry="r"
if [ -n "$uFQDNS" ]; then
for d in $uFQDNS; do
dinc=false
for c in $uCERTFQDNS; do
[ "$d" = "$c" ] && dinc=true && break
done
! $dinc && status_crt_fqdns="r" && break
done
fi
fi
fi
if ! $_LOW_PRIV_TLS_REFRESH; then
[ -d "$uCHROOT" ] && status_chroot_exists="g" || status_chroot_exists="r"
[ -r "$uPOOL" ] && status_pool_exists="g" || status_pool_exists="r" && [ -r "$uPOOL.disabled" ] && status_pool_exists="y"
group_exists "$uUSERNAME" && status_usergroup_exists="g" || status_usergroup_exists="r"
check_file_permissions "$uUSERNAME" &> /dev/null && status_fileperms="g" || status_fileperms="r"
is_any_unbound "$uUSERNAME" && status_binds="r" || status_binds="g"
check_config
fi
case "$_OPT_ACTION" in
list)
get_user_list
;;
status)
printf "$pf0" "USERNAME" "$uUSERNAME" "`status $status_user_exists 'OK' '' 'INVALID'`"
[ "$status_usergroup_exists" = "g" ] && statusMsg="$uUSERNAME" || statusMsg="No group \"$uUSERNAME\""
printf "$pf0" "USERGROUP" "$statusMsg" "`status $status_usergroup_exists 'OK' '' 'MISSING'`"
printf "$pf0" "PHP-FPM-CHROOT" "$uCHROOT" "`status $status_chroot_exists 'OK' '' 'MISSING'`"
printf "$pf0" "PHP-FPM-POOL" "$uPOOL" "`status $status_pool_exists 'ENABLED' 'DISABLED' 'MISSING'`"
printf "$pf0" "NGINX CONFIG" "$uNGINX" "`status $status_nginx_exists 'ENABLED' 'DISABLED' 'MISSING'`"
if [ "$status_nginx_exists" != "r" ]; then
printf "$pf0" "FQDNs" "`get_FQDNs_for_user \"$uUSERNAME\" | wc -l`"
get_FQDNs_for_user "$uUSERNAME" | while read fqdn; do
printf "$pf1" "" "$fqdn"
done;
else
printf "$pf0" "FQDNs" "Unknown (NGINX config missing)" "`status y '' 'UNKNOWN'`"
fi
if $_LETS_ENCRYPT_ENABLE; then
if [ "$status_crt_exists" != "g" ]; then
printf "$pf0" "TLS CERTIFICATE" "Missing" "`status r '' '' 'MISSING'`"
else
case "$status_crt_expiry" in
g) statusMsg="valid";;
y) statusMsg="expiring";;
r) statusMsg="expired";;
esac
status="$status_crt_expiry"
[ "$status_crt_fqdns" = "r" ] && statusMsg="$statusMsg, domains missing" && status="r"
printf "$pf0" "TLS CERTIFICATE" "Exists, $statusMsg" "`status $status 'OK' 'EXPIRING' 'ERROR'`"
if [ "$status_crt_fqdns" = "r" ]; then
allFqdnsInCert=true
for fqdn in $uFQDNS; do
fqdnInCert=false
for certfqdn in $uCERTFQDNS; do
[ "$fqdn" = "$certfqdn" ] && fqdnInCert=true && break
done
! $fqdnInCert && printf "$pf1" "" "$fqdn not in certificate" && allFqdnsInCert=false
done
else
[ "$status_nginx_exists" = "r" ] && printf "$pf0" "TLS CERTIFICATE" "Unknown (NGINX config missing)" "`status y '' 'UNKNOWN'`"
fi
fi
fi
if [ "$status_chroot_exists" != "r" ]; then
printf "$pf0" "FILE PERMISSIONS" "`[ "$status_fileperms" = "g" ] && echo -n \"All correct\" || echo -n \"Incorrect\"`" "`status $status_fileperms 'OK' '' 'INCORRECT'`"
fix_or_check_file_permissions "$uUSERNAME"
else
printf "$pf0" "FILE PERMISSIONS" "Unknown (PHP-FPM-CHROOT missing)" "`status y '' 'UNKNOWN'`"
fi
if [ "$status_chroot_exists" != "r" ] ; then
printf "$pf0" "CHROOT BINDS" "`[ "$status_binds" = "g" ] && echo -n \"All bound\" || echo -n \"Binds missing\"`" "`status $status_binds 'OK' '' 'MISSING'`"
if [ "$status_binds" != "g" ]; then
for bind in `get_user_binds "$uUSERNAME"`; do
! is_bound "$uCHROOT$bind" && printf "$pf1" "" "$bind missing"
done
fi
else
printf "$pf0" "CHROOT BINDS" "Unknown (PHP-FPM-CHROOT missing)" "`status y '' 'UNKNOWN'`"
fi
# Return value
checkList="status_user_exists status_chroot_exists status_pool_exists status_nginx_exists status_usergroup_exists status_fileperms status_binds status_crt_exists status_crt_expiry status_crt_fqdns"
for check in $checkList; do [ "${!check}" = "r" ] && stop 1; done
stop 0
;;
fixperm)
if [ "$status_chroot_exists" == "r" ]; then
printf "$pf2" "Chroot does not exist. Please create manually." "`status r '' '' 'ERROR'`"
stop 1
else
fix_or_check_file_permissions "$uUSERNAME" fix
stop $?
fi
;;
binds)
returnValue=0
if [ "$_OPT_ACTION_BIND" = "systemd" ]; then
! $_SYSTEMD_ENABLE && stop 0
# List systemd unit files
[ "$_OPT_ACTION_BIND_SYSTEMD" = "list" ] && list_systemd_units && stop 0
# Set up systemd unit files
[ "$_OPT_ACTION_BIND_SYSTEMD" = "create" ] && create_systemd_units && stop 0
# Clean up systemd unit files
[ "$_OPT_ACTION_BIND_SYSTEMD" = "clean" ] && delete_systemd_units && stop 0
# Update systemd unit files
[ "$_OPT_ACTION_BIND_SYSTEMD" = "update" ] && $0 _INTERNAL_ binds systemd clean -Y && $0 _INTERNAL_ binds systemd create && systemctl daemon-reload && stop 0
stop 1
fi
if [ "$status_chroot_exists" != "g" ]; then
printf "$pf2" "Chroot \"$uCHROOT\" does not exist." "`status r '' '' 'ERROR'`"
stop 1
fi
for bind in `get_user_binds "$uUSERNAME"`; do
if [ "$_OPT_ACTION_BIND" = "list" ]; then
echo "$bind"
continue
fi
if [ "$_OPT_ACTION_BIND" = "status" ]; then
status_bind="r" && is_bound "$uCHROOT$bind" && status_bind="g"
printf "$pf2" "$bind" "`status $status_bind 'BOUND' '' 'UNBOUND'`"
[ "$status_bind" = "r" ] && returnValue=1
continue
fi
# if [ "$status_nginx_exists" = "g" -o "$status_pool_exists" = "g" ]; then
# printf "$pf2" "Please disable webspace first." "`status r '' '' 'ERROR'`"
# stop 1
# fi
if [ "$_OPT_ACTION_BIND" = "bind" ] && ! is_bound "$uCHROOT$bind"; then
# Create mointpoints
if [ ! -e "$uCHROOT$bind" ]; then
if [ -d "$bind" ]; then
status="r"
mkdir -p "$uCHROOT$bind" && status="g" || returnValue=1
printf "$pf2" "Creating mountpoint $uCHROOT$bind (dir)" "`status $status 'DONE' '' 'FAILED'`"
else
dir="$uCHROOT`dirname $bind`"
status="r"
mkdir -p "$dir" && status="g" || returnValue=1
printf "$pf2" "Creating directory $dir" "`status $status 'DONE' '' 'FAILED'`"
status="r"
touch "$uCHROOT$bind" && status="g" || returnValue=1
printf "$pf2" "Creating mountpoint $uCHROOT$bind (file)" "`status $status 'DONE' '' 'FAILED'`"
fi
fi
if [ $returnValue -eq 0 ]; then
status="r"
mount --bind "$bind" "$uCHROOT$bind" && status="g" || returnValue=1
printf "$pf2" "Mount $uCHROOT$bind" "`status $status 'DONE' '' 'FAILED'`"
[ "$status" = "g" ] && status="r" && mount -o "remount,ro,bind" "$bind" "$uCHROOT$bind" && status="g" || returnValue=1
printf "$pf2" "Remount $uCHROOT$bind readonly" "`status $status 'DONE' '' 'FAILED'`"
else
printf "$pf" "Mount $uCHROOT$bind" "`status y '' 'SKIPPED'`"
fi
fi
if [ "$_OPT_ACTION_BIND" = "unbind" -o "$_OPT_ACTION_BIND" = "clean" ] && is_bound "$uCHROOT$bind"; then
status="r"
umount "$uCHROOT$bind" && status="g" || returnValue=1
printf "$pf2" "Umount $uCHROOT$bind" "`status $status 'DONE' '' 'FAILED'`"
fi
done;
if [ "$_OPT_ACTION_BIND" = "clean" ]; then
deletePathes=()
allPathes=()
for bind in `get_user_binds "$uUSERNAME"`; do
deletePath="`get_base_path \"$bind\"`"
inList=false
for e in "${allPathes[@]}"; do
[ "$e" = "$uCHROOT$deletePath" ] && inList=true
done
$inList || allPathes+=("$uCHROOT$deletePath")
if ! $inList; then
if [ ! -e "$uCHROOT$deletePath" ]; then
printf "$pf2" "$uCHROOT$deletePath - does not exist" "`status y '' 'SKIPPED'`"
continue
fi
if is_bound "$uCHROOT$bind"; then
printf "$pf2" "$uCHROOT$deletePath - still mounted" "`status r '' '' 'ERROR'`"
continue
fi
deletePathes+=("$uCHROOT$deletePath")
fi
done
[ "${#deletePathes}" -eq 0 ] && stop $returnValue
if ! $_OPT_YES; then
echo -e "\nWill execute the following commands in order:\n"
for i in `seq 0 $((${#deletePathes[@]}-1))`; do
echo -e "\trm -rf \"${deletePathes[$i]}\""
done;
echo
fi
while [ "$commandsOK" != "y" -a "$commandsOK" != "n" ]; do
! $_OPT_YES && read -p "Are you OK with that? [y/n]: " commandsOK
$_OPT_YES && commandsOK="y"
if [ "$commandsOK" = "y" ]; then
! $_OPT_YES && echo
for i in `seq 0 $((${#deletePathes[@]}-1))`; do
cmd_status="r"
rm -rf "${deletePathes[$i]}"
[ "$?" -eq 0 ] && cmd_status="g"
printf "$pf2" "Delete ${deletePathes[$i]}" "`status "$cmd_status" 'DONE' '' 'FAILED'`"
[ "$cmd_status" = "g" ] || returnValue=1
done;
fi
if [ "$commandsOK" = "n" ]; then
printf "$pf2" "Aborted by user." "`status y '' 'SKIPPED'`"
fi
done
fi
stop $returnValue
;;
enable|disable)
status="r"
[ "$status_pool_exists" = "r" ] && printf "$pf2" "\"$uPOOL\" missing." "`status r '' '' 'ERROR'`" && stop 1
[ "$status_nginx_exists" = "r" ] && printf "$pf2" "\"$uNGINX\" missing." "`status r '' '' 'ERROR'`" && stop 1
[ "$status_pool_exists" != "$status_nginx_exists" ] && printf "$pf2" "POOL and NGINX config not in same state." "`status r '' '' 'ERROR'`" && stop 1
if [ "$_OPT_ACTION" = "enable" ]; then
[ "$status_pool_exists" = "g" ] && printf "$pf2" "Webspace already enabled." "`status y '' 'SKIPPED' ''`" && stop 0
! $0 _INTERNAL_ status "$uUSERNAME" &> /dev/null && printf "$pf2" "Webspace can not be enabled. Run \"$0 status $uUSERNAME\" to see why." "`status r '' '' 'ERROR'`" && stop 1
mv "$uPOOL.disabled" "$uPOOL" && status="g"
[ "$status" = "g" ] && status="r" && mv "$uNGINX.disabled" "$uNGINX" && status="g"
printf "$pf2" "Webspace enabled" "`status $status 'ENABLED' '' 'FAILED'`"
[ "$status" = "g" ] || stop 1
elif [ "$_OPT_ACTION" = "disable" ]; then
[ "$status_pool_exists" = "y" ] && printf "$pf2" "Webspace already disabled." "`status y '' 'SKIPPED' ''`" && stop 0
mv "$uPOOL" "$uPOOL.disabled" && status="g"
[ "$status" = "g" ] && status="r" && mv "$uNGINX" "$uNGINX.disabled" && status="g"
printf "$pf2" "Webspace disabled" "`status $status 'DISABLED' '' 'FAILED'`"
[ "$status" = "g" ] || stop 1
fi
reload_services || stop 1
;;
create)
returnValue=0
reset_nscd
! user_is_valid "$_OPT_USERNAME" && printf "$pf2" "Invalid username ([a-zA-Z0-9]{4,10})" "`status r '' '' 'ERROR'`" && stop 1
if user_create "$_OPT_USERNAME"; then
printf "$pf2" "Run _USER_CREATE_CMD..." "`status g 'DONE'`"
else
printf "$pf2" "Run _USER_CREATE_CMD..." "`status r '' '' 'FAILED'`"
stop 1
fi
status="r"
eval "${_NGINX_ADD_GROUP_CMD//@USERNAME@/$_OPT_USERNAME}" && status="g"
printf "$pf2" "Run _NGINX_ADD_GROUP_CMD..." "`status $status 'DONE' '' 'FAILED'`"
[ "$status" = "g" ] || returnValue=1
! id "$_OPT_USERNAME" &> /dev/null && printf "$pf2" "User \"$_OPT_USERNAME\" not found in system." "`status r '' '' 'ERROR'`" && stop 1
! group_exists "$_OPT_USERNAME" && printf "$pf2" "No group \"$_OPT_USERNAME\" found in system." "`status r '' '' 'ERROR'`" && stop 1
uCHROOT="`get_user_chroot \"$_OPT_USERNAME\"`"
if [ ! -d "$uCHROOT" ]; then
status="r"
mkdir -p "$uCHROOT" && status="g"
printf "$pf2" "Create chroot \"$uCHROOT\"" "`status $status 'DONE' '' 'FAILED'`"
fi
[ ! -d "$uCHROOT" ] && printf "$pf2" "Chroot \"$uCHROOT\" does not exist." "`status r '' '' 'ERROR'`" && stop 1
domains="$_OPT_DOMAINS"
if [ -z "$domains" ]; then
# Ask for domain list
echo
printf "$pf2" "Please specify at least one domain for the new webspace."
printf "$pf2" "Finish list with empty input."
domains=""
while true; do
read -p "FQDN: " fqdn
fqdn="`echo -e \"$fqdn\" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'`"
[ -z "$fqdn" -a -n "$domains" ] && break
if is_valid_fqdn "$fqdn"; then
domains="$domains $fqdn"
else
printf "$pf2" "Not a valid domain." "`status r '' '' 'ERROR'`"
fi
done
domains="`echo -e \"$domains\" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'`"
fi
echo
install_template "$_NGINX_CONF_TEMPLATE" "${_NGINX_CONF//@USERNAME@/$_OPT_USERNAME}.disabled" "$_NGINX_CONF_TEMPLATE_OWNER" "$_NGINX_CONF_TEMPLATE_MODE" "USERNAME" "$_OPT_USERNAME" "DOMAINS" "$domains" || returnValue=1
install_template "$_PHP_FPM_CONF_TEMPLATE" "${_PHP_FPM_CONF//@USERNAME@/$_OPT_USERNAME}.disabled" "$_PHP_FPM_CONF_TEMPLATE_OWNER" "$_PHP_FPM_CONF_TEMPLATE_MODE" "USERNAME" "$_OPT_USERNAME" || returnValue=1
echo
$0 _INTERNAL_ fixperm "$_OPT_USERNAME" || returnValue=1
echo
$0 _INTERNAL_ binds bind "$_OPT_USERNAME" || returnValue=1
status="r"
$0 _INTERNAL_ binds systemd update > /dev/null && status="g"
[ "$status" = "g" ] || returnValue=1
printf "$pf2" "Update systemd units for chroot binds..." "`status $status 'DONE' '' 'FAILED'`"
if $_LETS_ENCRYPT_ENABLE; then
echo
$0 _INTERNAL_ tls refresh "$_OPT_USERNAME"
fi
if [ -n "$_POST_CREATE_CMD" ]; then
echo
status="r"
eval "${_POST_CREATE_CMD//@USERNAME@/$_OPT_USERNAME}" && status="g"
[ "$status" = "g" ] || returnValue=1
printf "$pf2" "Run _POST_CREATE_CMD..." "`status $status 'DONE' '' 'FAILED'`"
fi
stop $returnValue
;;
delete)
if [ "$status_nginx_exists" = "g" -o "$status_pool_exists" = "g" ]; then
printf "$pf2" "Please disable webspace first." "`status r '' '' 'ERROR'`"
stop 1
fi
deleteCmd[0]="rm \"${_NGINX_CONF//@USERNAME@/$uUSERNAME}.disabled\""
deleteCmd[1]="rm \"${_PHP_FPM_CONF//@USERNAME@/$uUSERNAME}.disabled\""
deleteCmd[2]="rm -f \"$uCERT\""
deleteCmd[3]="rm -f \"$_LETS_ENCRYPT_CSR_DIR/$uUSERNAME.csr\""
deleteCmd[4]="rm -r \"${_PHP_FPM_CHROOT//@USERNAME@/$uUSERNAME}\""
deleteCmd[5]="${_USER_DELETE_CMD//@USERNAME@/$uUSERNAME}"
if ! $_OPT_YES; then
echo -e "Will execute the following commands in order:\n"
for i in `seq 0 $((${#deleteCmd[@]}-1))`; do
echo -e "\t${deleteCmd[$i]}"
done;
echo
fi
returnValue=0
while [ "$commandsOK" != "y" -a "$commandsOK" != "n" ]; do
! $_OPT_YES && read -p "Are you OK with that? [y/n]: " commandsOK
$_OPT_YES && commandsOK="y"
if [ "$commandsOK" = "y" ]; then
! $_OPT_YES && echo
if is_any_bound "$uUSERNAME"; then
$0 _INTERNAL_ binds unbind "$uUSERNAME"
[ "$?" -ne 0 ] && printf "$pf2" "Unbind failed." "`status r '' '' 'ERROR'`" && stop 1
fi
for i in `seq 0 $((${#deleteCmd[@]}-1))`; do
cmd_status="r"
eval "${deleteCmd[$i]}"
[ "$?" -eq 0 ] && cmd_status="g"
printf "$pf2" "${deleteCmd[$i]}" "`status "$cmd_status" 'DONE' '' 'FAILED'`"
[ "$cmd_status" = "g" ] || returnValue=1
done;
fi
if [ "$commandsOK" = "n" ]; then
printf "$pf2" "Aborted by user." "`status y '' 'SKIPPED'`"
stop 1
fi
done
reset_nscd
status="r"
$0 _INTERNAL_ binds systemd update > /dev/null && status="g"
[ "$status" = "g" ] || returnValue=1
printf "$pf2" "Update systemd units for chroot binds..." "`status $status 'DONE' '' 'FAILED'`"
stop $returnValue
;;
tls)
! $_LETS_ENCRYPT_ENABLE && printf "$pf2" "Let's Encrypt functionality is not enabled." "`status r '' '' 'ERROR'`" && stop 1
# Check if we can use _LETS_ENCRYPT_USER
if ! le_cmd "true"; then
printf "$pf2" "Could not run as \"$_LETS_ENCRYPT_USER\"" "`status r '' '' 'ERROR'`"
stop 1
fi
# Check/setup _LETS_ENCRYPT_CRT/CSR/CHALLENGE_DIR
for d in CRT CSR CHALLENGE; do
dir="`eval echo \\$_LETS_ENCRYPT_${d}_DIR`"
eval "status_${d}_dir=\"y\""
le_cmd "[ -d \"$dir\" -a -w \"$dir\" ]" && eval "status_${d}_dir=\"g\""
[ "`eval echo \\$status_${d}_dir`" = "y" -a "$_OPT_ACTION_TLS" != "init" ] && eval "status_${d}_dir=\"r\""
status="`eval echo \\$status_${d}_dir`"
printf "$pf2" "_LETS_ENCRYPT_${d}_DIR exists and writable by $_LETS_ENCRYPT_USER" "`status $status 'YES' 'NO' 'NO'`"
[ "$status" = "r" ] && stop 1
if [ "$status" = "y" ]; then
create_owner="$_LETS_ENCRYPT_USER:$_NGINX_USERGROUP"
create_mode="0710"
if [ "$d" = "CSR" ]; then
create_owner="$_LETS_ENCRYPT_USER:$_LETS_ENCRYPT_USERGROUP"
create_mode="0700"
fi
status_create="r"
mkdir -p "$dir" && status_create="g"
printf "$pf2" "Create $dir" "`status $status_create 'DONE' '' 'FAILED'`"
[ "$status_create" = "g" ] && status_create="r" && chown "$create_owner" "$dir" && chmod "$create_mode" "$dir" && status_create="g"
printf "$pf2" "Setting permissions to $create_owner mode $create_mode" "`status $status_create 'DONE' '' 'FAILED'`"
[ "$status_create" != "g" ] && stop 1
fi
done
# Check/setup Account and Server key
for k in ACCOUNT SERVER; do
keyPath="`eval echo \\$_LETS_ENCRYPT_${k}_KEY`"
eval "status_${k}_key=\"y\""
le_cmd "[ -r \"$keyPath\" ]" && eval "status_${k}_key=\"g\""
[ "`eval echo \\$status_${k}_key`" = "y" -a "$_OPT_ACTION_TLS" != "init" ] && eval "status_${k}_key=\"r\""
status="`eval echo \\$status_${k}_key`"
printf "$pf2" "_LETS_ENCRYPT_${k}_KEY exists and readable by $_LETS_ENCRYPT_USER" "`status $status 'YES' 'NO' 'NO'`"
[ "$status" = "r" ] && stop 1
if [ "$status" = "y" ]; then
create_owner="$_LETS_ENCRYPT_USER:$_NGINX_USERGROUP"
create_mode="0440"
if [ "$k" = "ACCOUNT" ]; then
create_owner="$_LETS_ENCRYPT_USER:$_LETS_ENCRYPT_USERGROUP"
create_mode="0400"
fi;
status_create="r"
openssl genrsa $_LETS_ENCRYPT_KEYLENGTH > "$keyPath" && status_create="g"
printf "$pf2" "Generate _LETS_ENCRYPT_${k}_KEY" "`status $status_create 'DONE' '' 'FAILED'`"
[ "$status_create" = "g" ] && status_create="r" && chown "$create_owner" "$keyPath" && chmod "$create_mode" "$keyPath" && status_create="g"
printf "$pf2" "Setting permissions to $create_owner mode $create_mode" "`status $status_create 'DONE' '' 'FAILED'`"
[ "$status_create" != "g" ] && stop 1
fi
done
# Check/setup dhparams
status_dhparams_exists="y"
le_cmd "[ -r \"$_LETS_ENCRYPT_DHPARAMS\" ]" && status_dhparams_exists="g"
[ "$status_dhparams_exists" = "y" -a "$_OPT_ACTION_TLS" != "init" ] && status_dhparams_exists="r"
printf "$pf2" "_LETS_ENCRYPT_DHPARAMS exists and readable by $_LETS_ENCRYPT_USER" "`status $status_dhparams_exists 'YES' 'NO' 'NO'`"
[ "$status_dhparams_exists" = "r" ] && stop 1
if [ "$status_dhparams_exists" = "y" ]; then
status_create="r"
openssl dhparam -out "$_LETS_ENCRYPT_DHPARAMS" $_LETS_ENCRYPT_DHPARAMS_LENGTH > "$_LETS_ENCRYPT_DHPARAMS" && status_create="g"
printf "$pf2" "Generating _LETS_ENCRYPT_DHPARAMS..." "`status $status_create 'DONE' '' 'FAILED'`"
[ "$status_create" = "g" ] && status_create="r" && chown "$_LETS_ENCRYPT_USER:$_NGINX_USERGROUP" "$_LETS_ENCRYPT_DHPARAMS" && chmod "440" "$_LETS_ENCRYPT_DHPARAMS" && status_create="g"
printf "$pf2" "Setting permissions to $_LETS_ENCRYPT_USER:$_NGINX_USERGROUP mode 440" "`status $status_create 'DONE' '' 'FAILED'`"
[ "$status_create" != "g" ] && stop 1
fi
# Check/setup intermediate certificate
status_crt_intermediate_exists="y"
le_cmd "[ -r \"$_LETS_ENCRYPT_INTERMEDIATE\" ]" && status_crt_intermediate_exists="g"
[ "$status_crt_intermediate_exists" = "y" -a "$_OPT_ACTION_TLS" != "init" ] && status_crt_intermediate_exists="r"
printf "$pf2" "_LETS_ENCRYPT_INTERMEDIATE exists and readable by $_LETS_ENCRYPT_USER" "`status $status_crt_intermediate_exists 'YES' 'NO' 'NO'`"
[ "$status_crt_intermediate_exists" = "r" ] && stop 1
if [ "$status_crt_intermediate_exists" = "y" ]; then
status_create="r"
wget -O- "$_LETS_ENCRYPT_INTERMEDIATE_URL" > "$_LETS_ENCRYPT_INTERMEDIATE" && status_create="g"
printf "$pf2" "Downloading _LETS_ENCRYPT_INTERMEDIATE..." "`status $status_create 'DONE' '' 'FAILED'`"
[ "$status_create" = "g" ] && status_create="r" && chown "$_LETS_ENCRYPT_USER:$_NGINX_USERGROUP" "$_LETS_ENCRYPT_INTERMEDIATE" && chmod "440" "$_LETS_ENCRYPT_INTERMEDIATE" && status_create="g"
printf "$pf2" "Setting permissions to $_LETS_ENCRYPT_USER:$_NGINX_USERGROUP mode 440" "`status $status_create 'DONE' '' 'FAILED'`"
[ "$status_create" != "g" ] && stop 1
fi
if [ "$_OPT_ACTION_TLS" = "refresh" ]; then
[ "$status_nginx_exists" = "r" ] && printf "$pf2" "NGINX config could not be read" "`status r '' '' 'ERROR'`" && stop 1
[ -z "$uFQDNS" ] && printf "$pf2" "No domains for $uUSERNAME" "`status r '' '' 'ERROR'`" && stop 1
proceed=false
if ! $_OPT_ACTION_TLS_FORCEREFRESH; then
status="$status_crt_exists"
[ "$status" = "r" ] && status="y"
printf "$pf2" "Checking existance..." "`status $status 'YES' 'NO' ''`"
[ "$status" != "g" ] && proceed=true
if ! $proceed; then
status="$status_crt_expiry"
[ "$status" != "r" ] && printf "$pf2" "Checking expiry..." "`status $status 'VALID' 'EXPIRING' ''`"
[ "$status" = "r" ] && printf "$pf2" "Checking expiry..." "`status r '' 'EXPIRED' ''`"
[ "$status" != "g" ] && proceed=true
fi
if ! $proceed; then
status="$status_crt_fqdns"
[ "$status" = "r" ] && status="y"
printf "$pf2" "Checking all domains available in cert..." "`status $status 'OK' 'MISSING' ''`"
[ "$status" != "g" ] && proceed=true
fi
else
proceed=true
fi
! $proceed && printf "$pf2" "No reason to refresh certificate for $uUSERNAME" "`status y '' 'SKIPPING' ''`" && stop 0
status="r"
csr_path="$_LETS_ENCRYPT_CSR_DIR/$uUSERNAME.csr"
if [ "`echo \"$uFQDNS\" | wc -w`" -eq 1 ]; then
le_cmd "openssl req -new -sha256 -key \"$_LETS_ENCRYPT_SERVER_KEY\" -subj \"/CN=$uFQDNS\" > \"$csr_path\"" && status="g"
else
san="DNS:`echo $uFQDNS | sed -e 's/ /,DNS:/g'`"
le_cmd "openssl req -new -sha256 -key \"$_LETS_ENCRYPT_SERVER_KEY\" -subj \"/\" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf \"[SAN]\nsubjectAltName=$san\")) > \"$csr_path\"" && status="g"
fi
printf "$pf2" "Creating CSR for $uUSERNAME..." "`status $status 'OK' '' 'FAILED'`"
[ "$status" = "r" ] && stop 1
status="r" && le_cmd "chown \"$_LETS_ENCRYPT_USER:$_LETS_ENCRYPT_USERGROUP\" \"$csr_path\"" && status="g"
printf "$pf2" "Set owner to $_LETS_ENCRYPT_USER:$_LETS_ENCRYPT_USERGROUP" "`status $status 'OK' '' 'FAILED'`"
[ "$status" = "r" ] && stop 1
status="r" && le_cmd "chmod $_LETS_ENCRYPT_CSR_MODE \"$csr_path\"" && status="g"
printf "$pf2" "Set mode to $_LETS_ENCRYPT_CSR_MODE" "`status $status 'OK' '' 'FAILED'`"
[ "$status" = "r" ] && stop 1
status="r"
le_cmd "$_LETS_ENCRYPT_ACME_TINY --account-key \"$_LETS_ENCRYPT_ACCOUNT_KEY\" --csr \"$csr_path\" --acme-dir \"$_LETS_ENCRYPT_CHALLENGE_DIR\" > \"$uCERT.signed\"" && status="g"
printf "$pf2" "Request certificate for $uUSERNAME" "`status $status 'OK' '' 'FAILED'`"
[ "$status" = "r" ] && le_cmd "rm -f $uCERT.signed" && stop 1
status="r" && le_cmd "cat \"$uCERT.signed\" \"$_LETS_ENCRYPT_INTERMEDIATE\" > \"$uCERT.chained\"" && status="g"
printf "$pf2" "Chaining certifiacte..." "`status $status 'OK' '' 'FAILED'`"
[ "$status" = "r" ] && le_cmd "rm -f $uCERT.chained" && stop 1
status="r" && le_cmd "mv \"$uCERT.chained\" \"$uCERT\"" && status="g"
printf "$pf2" "Putting new cert in place" "`status $status 'OK' '' 'FAILED'`"
[ "$status" = "r" ] && stop 1
status="r" && le_cmd "rm \"$uCERT.signed\"" && status="g"
printf "$pf2" "Removing unchained certificate" "`status $status 'OK' '' 'FAILED'`"
[ "$status" = "r" ] && stop 1
status="r" && le_cmd "chown "$_LETS_ENCRYPT_USER:$_LETS_ENCRYPT_USERGROUP" \"$uCERT\"" && status="g"
printf "$pf2" "Set owner to $_LETS_ENCRYPT_USER:$_LETS_ENCRYPT_USERGROUP" "`status $status 'OK' '' 'FAILED'`"
[ "$status" = "r" ] && stop 1
status="r" && le_cmd "chmod $_LETS_ENCRYPT_CRT_MODE \"$uCERT\"" && status="g"
printf "$pf2" "Set mode to $_LETS_ENCRYPT_CRT_MODE" "`status $status 'OK' '' 'FAILED'`"
[ "$status" = "r" ] && stop 1
reload_services "nginx" "sudo" || stop 1
fi
;;
help)
cat <<END
Usage: $0 <command> [<subcommand [<subcommand>]] [<username>] [-n|-Y]
<command> can be one of...
list:
List all usernames associated with webspaces
create <username>:
Create a webspace, and associate with <username>
status <username>:
Show status of webspace associated with <username>
enable <username> [-n]:
Enable webspace associated with <username>
-n prevents reload of services
disable <username> [-n]:
Disable webspace associated with <username>
-n prevents reload of services
delete <username>:
Delete webspace associated with <username>
fixperm <username>:
Set permissions and ownerships in PHP-FPM chroot
of <username> as defined in _PHP_FPM_CHROOT_DIRS
binds list|status|bind|unbind|clean [-Y] <username>:
list:
List binds for <username>
status:
Show mount status of binds for <username>
bind:
Mount all binds for <username>'s chroot. Mountpoints
will be created if they do not exist.
undbind:
Unmount all binds for <username>.
clean:
Unmount all binds for <username> and delete
mountpoints for binds. Without -Y it will
just list the pathes that would be deleted and
ask for confirmation interactively.
binds systemd list|create|update|clean [-Y]
These commands manage unit files for systemd to
automatically create mountpoints for users on boot
and mount binds for the user's chroots.
list:
List all systemd unit files managed by this script.
create:
Create systemd units for all users.
update:
Same as
$0 binds systemd clean -Y && $0 binds systemd create
This is idempotent and will bring the unitfiles in sync
with the user's chroot binds.
clean [-Y]:
Delete all unit files managed by this script. Without -Y it will
just list the pathes that would be deleted and
ask for confirmation interactively.
tls <subcommand> [<username>]:
_LETS_ENCRYPT_ENABLE must be set to "true" to use these commands
<subcommand> can be one of...
init:
Check preconditions and setup environment
(directories, keys) for requesting TLS
certificates using the "refresh" subcommand.
refresh <username> [-n]:
Request and apply certificate for webspace
associated with <username> if no certificate
is available, or if the actual certificate is
expired or about to expire.
-n prevents reload of services
forcerefresh <username> [-n]:
Same as "refresh" but always gets a new certificate
-n prevents reload of services
END
stop 1
;;
esac