nutools/lib/ulib/apache.tools

615 lines
22 KiB
Bash

##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
## Outils de haut niveau pour gérer apache et sa configuration
##@cooked nocomments
##@require base
##@require sysinfos
##@require apache
uprovide apache.tools
urequire base sysinfos apache
function __apache_resolvcert() {
[ -n "$__rc_dir" ] || __rc_dir="$(dirname "$__rc_conf")"
eval "$(
source "$__rc_conf"
set_var_cmd __rc_cert "$cert"
set_var_cmd __rc_key "$key"
set_var_cmd __rc_ca "$ca"
)"
[ -n "$__rc_cert" ] && __rc_cert="$(abspath "$__rc_cert" "$__rc_dir")"
[ -n "$__rc_key" ] && __rc_key="$(abspath "$__rc_key" "$__rc_dir")"
[ -n "$__rc_ca" ] && __rc_ca="$(abspath "$__rc_ca" "$__rc_dir")"
}
function __apache_checkvars() {
if [ -n "$__rc_cert" -a -z "$__rc_key" ]; then
local __rc_name __rc_ext
splitname "$__rc_cert" __rc_name __rc_ext
if [ "$__rc_ext" == "crt" -o "$__rc_ext" == "pem" ]; then
__rc_key="$__rc_name.key"
enote "La clé privée n'a pas été spécifiée. La valeur $(ppath "$__rc_key") sera utilisée"
else
eerror "Impossible de trouver la clé privée correspondant au certificat $(ppath "$__rc_cert")"
return 1
fi
fi
if [ -z "$__rc_cert" -a -z "$__rc_ca" ]; then
eerror "Vous devez spécifier le certificat à installer"
return 1
elif [ -z "$__rc_cert" ]; then
eattention "Seul le certificat autorité a été spécifié."
elif [ -z "$__rc_ca" ]; then
ewarn "Aucun certificat autorité n'a pas été spécifié. Cela ne peut marcher que si le certificat est autosigné"
fi
local i
for i in "$__rc_cert" "$__rc_key" "$__rc_ca"; do
[ -n "$i" ] || continue
[ -f "$i" ] || {
eerror "$i: Fichier introuvable"
return 1
}
done
}
function apache_resolvecert() {
# Calculer l'emplacement des certificats correspondant aux arguments $1 et
# $2 (qui correspondent aux options --conf et --dir de apache_addcert()),
# puis initialiser les variables $3(=cert), $4(=key) et $5(=ca)
local __rc_conf="$1" __rc_dir="$2"
local __rc_cert __rc_key __rc_ca
__apache_resolvcert
__apache_checkvars || return 1
set_var "${3:-cert}" "$__rc_cert"
set_var "${4:-key}" "$__rc_key"
set_var "${5:-ca}" "$__rc_ca"
}
function apache_addcert() {
function __apache_addcert_display_help() {
uecho "apache_addcert: Installer un certificat sur le serveur
USAGE
apache_addcert [options] [cert.pem [cert.key [ca.pem]]]
OPTIONS
--conf certsconf
--dir certsdir
Spécifier un fichier de configuration et un répertoire depuis lesquels
prendre les informations sur les certificats à utiliser.
Le fichier de configuration doit définir les variables cert, key et ca
avec les noms des fichiers contenant respectivement le certificat, la
clé privée, et les certificats autorités, exprimés relativement au
répertoire certsdir.
Si ces options ne sont pas spécifiées, les fichiers doivent être donnés
sur la ligne de commande.
--out-cert cert
--out-key key
--out-ca ca
Au lieu d'installer les certificats, placer les chemins vers les
fichiers correspondant dans les variables spécifiées"
}
eval "$(utools_local)"
local action=install
local certsconf certsdir cert key ca
local __out_cert __out_key __out_ca
parse_opts "${PRETTYOPTS[@]}" \
--help '$exit_with __apache_addcert_display_help' \
-C:,--conf: certsconf= \
-d:,--dir: certsdir= \
--out-cert: '$set@ __out_cert; action=dump' \
--out-key: '$set@ __out_key; action=dump' \
--out-ca: '$set@ __out_ca; action=dump' \
@ args -- "$@" && set -- "${args[@]}" || die "$args"
local __rc_conf __rc_dir
local __rc_cert __rc_key __rc_ca
if [ -n "$certsconf" ]; then
__rc_conf="$certsconf"
__rc_dir="$certsdir"
__apache_resolvconf
__apache_checkvars || return 1
else
__rc_cert="$1"
__rc_key="$2"
__rc_ca="$3"
__apache_checkvars || return 1
fi
cert="$__rc_cert"
key="$__rc_key"
ca="$__rc_ca"
if [ -n "$cert" ]; then
estepi "Certificat: $(ppath "$cert")"
estepi "Clé privée: $(ppath "$key")"
fi
[ -n "$ca" ] && estepi "CAutorités: $(ppath "$ca")"
ask_yesno "Voulez-vous continuer?" O || return 1
urequire install
etitle "Installation des certificats"
certsdir="$(get_APACHESSLCERTSDIR_prefix)"
keysdir="$(get_APACHESSLKEYSDIR_prefix)"
if [ ! -d "$certsdir" ]; then
mkdir -p "$certsdir" || return 1
chmod 755 "$certsdir" || return 1
fi
if [ ! -d "$keysdir" ]; then
mkdir -p "$keysdir" || return 1
chmod 710 "$keysdir" || return 1
fi
if [ -n "$cert" ]; then
copy_replace "$cert" "$certsdir" || return 1
chmod 644 "$certsdir/$(basename "$cert")" || return 1
copy_replace "$key" "$keysdir" || return 1
chmod 640 "$keysdir/$(basename "$key")" || return 1
fi
if [ -n "$ca" ]; then
copy_replace "$ca" "$certsdir" || return 1
chmod 644 "$certsdir/$(basename "$ca")" || return 1
fi
eend
return 0
}
function __apache_autoconf_setup() {
if ! check_sysinfos --vars sysname sysdist sysver bits -s linux64 linux32 linux -d debian; then
eerror "apache_autoconf n'est supporté que sur Debian linux"
return 1
fi
urequire install
compute_apache_prefixes
return 0
}
function __apache_autoconf_fillxxx() {
local var name value first=1
for var in "$@"; do
splitvar "$var" name value
array_addu FILLVARS "$name"
[ -n "$first" ] || FILLSCRIPT="$FILLSCRIPT"$'\n'
FILLSCRIPT="${FILLSCRIPT}s/@@${name}@@/$(qseds "${value}")/g"
first=
done
# Il faut un fichier temporaire pour les remplacement de fichiers
ac_set_tmpfile FILLTEMP
}
function __apache_autoconf_fillcopy() {
# copier le fichier $1 vers le fichier $2. Si le fichier $1 contient l'une
# des variables du tableau $FILLVARS, corriger d'abord le fichier avec le
# script sed $FILLSCRIPT. Le fichier temporaire $FILLTEMP est utilisé pour
# le remplacement des valeurs. $3 contient le cas échéant des commandes sed
# supplémentaires
local src="$1" dest="$2" sedscript="$3" perms="${4:-go+rX}"
local var found
for var in "${FILLVARS[@]}"; do
if quietgrep "@@${var}@@" "$1"; then
found=1
break
fi
done
if [ "$found" ]; then
sed "$FILLSCRIPT
$sedscript" <"$src" >"$FILLTEMP"
src="$FILLTEMP"
fi
copy_update "$src" "$dest" "$perms"
}
__APACHE_AUTOCONF_HELP="\
--confdir CONFDIR
Spécifier l'emplacement des fichiers de configuration apache ainsi que des
fichiers 'confs.conf', 'modules.conf' et 'sites.conf'. Par défaut, prendre
le répertoire local DESTDIR.
--confsdir CONFSDIR
Spécifier l'emplacement des fichiers des configuration. Par défaut, utiliser
DESTDIR/confs si ce répertoire existe.
--modulesdir MODULESDIR
Spécifier l'emplacement des fichiers des modules. Par défaut, utiliser
DESTDIR/modules si ce répertoire existe.
--sitesdir SITESDIR
Spécifier l'emplacement des fichiers des sites. Par défaut, utiliser
DESTDIR/sites si ce répertoire existe.
--cgibindir CGIBINDIR
Spécifier l'emplacement des scripts cgi à installer. Par défaut, utiliser
DESTDIR/cgi-bin si ce répertoire existe.
--wwwdir WWWDIR
Spécifier l'emplacement des fichiers du serveur web. Par défaut, utiliser
DESTDIR/www si ce répertoire existe.
--certsconfdir CERTSCONFDIR
Spécifier l'emplacement des fichiers de configuration des certificats. Par
défaut, utiliser DESTDIR/certsconf si ce répertoire existe. Il faut alors
spécifier aussi CERTSDIR, l'emplacement des certificats à installer.
--rrdir RRDIR
Spécifier l'emplacement des fichiers de réécriture. Par défaut, utiliser
DESTDIR/RewriteRules si ce répertoire existe.
--no-restart
Ne pas redémarrer apache en cas de modification de la configuration"
function __display_apache_autoconf_help() { eecho "$__APACHE_AUTOCONF_HELP"; }
function apache_autoconf() {
eval "$(utools_local)"
local -a ignores
local autoconfdir certsdir confdir confsdir oneconf modulesdir onemodule
local sitesdir onesite cgibindir wwwdir certsconfdir rrdir onecms
local sysname sysdist sysver bits
local destconfsdir a2xconf
local restart=1
parse_opts "${PRETTYOPTS[@]}" \
--help '$exit_with __display_apache_autoconf_help' \
--ignore: ignores \
--confdir: confdir= \
--confsdir: confsdir= \
--one-conf: oneconf= \
--modulesdir: modulesdir= \
--one-module: onemodule= \
--sitesdir: sitesdir= \
--one-site: onesite= \
--cgibindir: cgibindir= \
--wwwdir: wwwdir= \
--certsconfdir: certsconfdir= \
--rrdir: rrdir= \
--no-restart restart= \
--sysname: sysname= \
--sysdist: sysdist= \
--sysver: sysver= \
-6,--squeeze sysver=squeeze \
-7,--wheezy sysver=wheezy \
-8,--jessie sysver=jessie \
--bits: bits= \
@ args -- "$@" && set -- "${args[@]}" || die "$args"
if [ -n "$sysname" -o -n "$sysdist" -o -n "$sysver" ]; then
ensure_sysinfos sysname sysdist sysver
else
sysname=("${MYSYSNAME[@]}")
sysdist=("${MYSYSDIST[@]}")
sysver=("${MYSYSVER[@]}")
bits="$MYBITS"
fi
__apache_autoconf_setup || return 1
if check_sysinfos --vars sysname sysdist sysver bits -d debian -v jessie+; then
destconfsdir="$APACHECONFDIR/conf-available"
a2xconf=1
elif check_sysinfos --vars sysname sysdist sysver bits -d debian; then
destconfsdir="$APACHECONFDIR/conf.d"
fi
# Configuration
autoconfdir="$1"; shift
[ -n "$autoconfdir" ] || {
eerror "Vous devez spécifier le répertoire de base de la configuration apache"
return 1
}
certsdir="$1"; shift
if [ -z "$confdir" -o -z "$confsdir" -o -z "$modulesdir" \
-o -z "$sitesdir" -o -z "$cgibindir" -o -z "$wwwdir" \
-o -z "$certsconfdir" -o -z "$rrdir" ]; then
[ -d "$autoconfdir" ] || {
eerror "$autoconfdir: répertoire invalide"
return 1
}
fi
[ -n "$confdir" ] || confdir="$autoconfdir"
[ -n "$confsdir" ] || confsdir="$autoconfdir/confs"
[ -n "$modulesdir" ] || modulesdir="$autoconfdir/modules"
[ -n "$sitesdir" ] || sitesdir="$autoconfdir/sites"
[ -n "$cgibindir" ] || cgibindir="$autoconfdir/cgi-bin"
[ -n "$wwwdir" ] || wwwdir="$autoconfdir/www"
[ -n "$certsconfdir" ] || certsconfdir="$autoconfdir/certsconf"
[ -n "$rrdir" ] || rrdir="$autoconfdir/RewriteRules"
[ -n "$oneconf" -o -n "$onemodule" -o -n "$onesite" ] && onecms=1
# Faire un script sed pour remplacer les variables spécifiées par leur
# valeur dans les fichiers
local -a FILLVARS; local FILLSCRIPT FILLTEMP
__apache_autoconf_fillxxx
# Copie des certificats
local modified rehash conf
if [ -d "$certsconfdir" ]; then
local -a certsconfs certspems
local certsconf certspem cert key ca
array_addu FILLVARS cert
array_addu FILLVARS key
array_addu FILLVARS ca
etitle "Installation des certificats"
array_lsfiles certsconfs "$certsconfdir" "*.conf"
for certsconf in "${certsconfs[@]}"; do
if [ -z "$certsdir" ]; then
eerror "CERTSDIR est requis si --certsconfdir est spécifié"
return 1
elif [ ! -d "$certsdir" ]; then
eerror "$certsdir: répertoire invalide"
return 1
fi
apache_resolvecert "$certsconf" "$certsdir" cert key ca || return 1
apache_addcert -y "$cert" "$key" "$ca"
modified=1
done
array_lsfiles certspems "$certsconfdir" "*.crt" "*.pem"
for certspem in "${certspems[@]}"; do
if copy_update "$certspem" "$APACHESSLCERTSDIR/$(basename -- "$certspem")"; then
modified=1
rehash=1
fi
done
eend
fi
# Gestion des configurations
if [ -d "$confsdir" -a \( -z "$onecms" -o -n "$oneconf" \) ]; then
local -a confs
local conf
etitle "Installation des configurations"
array_from_lines confs "$(list_files "$confsdir" "*.conf")"
for conf in "${confs[@]}"; do
[ -z "$oneconf" -o "$conf" == "$oneconf" ] || continue
estep "$conf"
__apache_autoconf_fillcopy \
"$confsdir/$conf" \
"$destconfsdir/$conf" && modified=1
done
eend
fi
# Gestion des modules
if [ -d "$modulesdir" -a \( -z "$onecms" -o -n "$onemodule" \) ]; then
local -a confs
local conf
etitle "Installation des configurations des modules"
array_from_lines confs "$(list_files "$modulesdir" "*.conf")"
for conf in "${confs[@]}"; do
[ -z "$onemodule" -o "$conf" == "$onemodule" ] || continue
estep "$conf"
__apache_autoconf_fillcopy \
"$modulesdir/$conf" \
"$APACHECONFDIR/mods-available/$conf" && modified=1
done
eend
fi
# Règles de réécriture
if [ -d "$rrdir" -a -z "$onecms" ]; then
local -a confs
local conf
etitle "Installation des règles de réécriture"
array_from_lines confs "$(list_files "$rrdir" "RewriteRules*.conf")"
for conf in "${confs[@]}"; do
estep "$conf"
__apache_autoconf_fillcopy \
"$rrdir/$conf" \
"$APACHECONFDIR/$conf" && modified=1
done
eend
fi
# Sites
local -a enablesites disablesites
if [ -d "$sitesdir" -a \( -z "$onecms" -o -n "$onesite" \) ]; then
local -a confs
local conf confname destconf certsconf
etitle "Installation des sites"
array_lsfiles confs "$sitesdir" "*.conf"
for conf in "${confs[@]}"; do
confname="$(basename "$conf")"
[ -z "$onesite" -o "$confname" == "$onesite" ] || continue
certsconf=
if [ "${confname%.ssl.conf}" != "$confname" ]; then
if [ -d "$certsconfdir" ]; then
certsconf="${confname%.ssl.conf}-certs.conf"
else
ewarn "$conf: fichier ignoré parce que --certsconfdir n'a pas été spécifié"
fi
fi
case "$destconf" in
default.conf) destconf=default;;
default.ssl.conf) destconf=default-ssl;;
*) destconf="$confname";;
esac
if [ -n "$certsconf" ]; then
certsconf="$certsconfdir/$certsconf"
if [ -f "$certsconf" ]; then
apache_resolvecert "$certsconf" "$certsdir" cert key ca || return 1
__apache_autoconf_fillcopy \
"$conf" \
"$APACHEAVSITESDIR/$destconf" "\
s#@@cert@@#$APACHESSLCERTSDIR/$(basename "$cert")#g
s#@@key@@#$APACHESSLKEYSDIR/$(basename "$key")#g
s#@@ca@@#$APACHESSLCERTSDIR/$(basename "$ca")#g
"
else
eerror "$(ppath "$certsconf"): fichier introuvable. Il a été ignoré"
fi
else
__apache_autoconf_fillcopy \
"$conf" \
"$APACHEAVSITESDIR/$destconf"
fi
enablesites=("${enablesites[@]}" "$destconf")
modified=1
done
eend
fi
# Fichiers de configuration
if [ -d "$confdir" -a -z "$onecms" ]; then
local -a confs
local conf
etitle "Configuration de base"
array_from_lines confs "$(list_files "$confdir")"
for conf in "${confs[@]}"; do
array_contains ignores "$conf" && continue
case "$conf" in
confs.conf|modules.conf|sites.conf) continue;;
esac
estep "$conf"
__apache_autoconf_fillcopy \
"$confdir/$conf" \
"$APACHECONFDIR/$conf" && modified=1
done
if [ -f "$confdir/confs.conf" -a -n "$a2xconf" ]; then
local -a confs
local conf
array_from_lines confs "$(<"$confdir/confs.conf" filter_conf)"
for conf in "${confs[@]}"; do
if [ "${conf#-}" != "$conf" ]; then
conf="${conf#-}"
estep "Désactivation de la configuration $conf"
a2disconf "$conf" && modified=1
else
conf="${conf#+}"
estep "Activation de la configuration $conf"
a2enconf "$conf" && modified=1
fi
done
fi
if [ -f "$confdir/modules.conf" ]; then
local -a modules
local module
array_from_lines modules "$(<"$confdir/modules.conf" filter_conf)"
for module in "${modules[@]}"; do
if [ "${module#-}" != "$module" ]; then
module="${module#-}"
estep "Désactivation du module $module"
a2dismod "$module" && modified=1
else
module="${module#+}"
estep "Activation du module $module"
a2enmod "$module" && modified=1
fi
done
fi
if [ -f "$confdir/sites.conf" ]; then
local -a sitesconfs; local sitesconf
array_from_lines sitesconfs "$(<"$confdir/sites.conf" filter_conf)"
if [ ${#sitesconfs[*]} -gt 0 ]; then
# si une configuration existe, ignorer la configuration
# automatique
enablesites=()
disablesites=()
for sitesconf in "${sitesconfs[@]}"; do
if [ "${sitesconf#+}" != "$sitesconf" ]; then
array_del disablesites "${sitesconf#+}"
array_add enablesites "${sitesconf#+}"
elif [ "${sitesconf#-}" != "$sitesconf" ]; then
array_del enablesites "${sitesconf#-}"
array_add disablesites "${sitesconf#-}"
else
array_del disablesites "$sitesconf"
array_add enablesites "$sitesconf"
fi
done
fi
fi
eend
fi
# Scripts CGI
if [ -d "$cgibindir" -a -z "$onecms" ]; then
etitle "Installation des scripts CGI"
cpdirnovcs "$cgibindir" "$CGIBINDIR"
eend
fi
# Contenu web
if [ -d "$wwwdir" -a -z "$onecms" ]; then
etitle "Installation des fichiers du serveur web"
cpdirnovcs "$wwwdir" "$HTDOCSDIR"
eend
fi
# Nettoyer le fichier temporaire
ac_clean "$FILLTEMP"
if [ -n "${enablesites[*]}" -o -n "${disablesites[*]}" ]; then
etitle "(dés)Activation des sites"
local site
for site in "${enablesites[@]}"; do
estep "Activation du site $site"
a2ensite "$site"
done
for site in "${disablesites[@]}"; do
estep "Désactivation du site $site"
a2dissite "$site"
done
eend
fi
if [ -n "$modified" ]; then
[ -n "$rehash" ] && elinedots "Hashage des certificats" c_rehash
if [ -n "$restart" ]; then
estep "Redémarrage d'apache"
"$APACHECTL" restart
fi
fi
}
function apache_autoconf_localhosts() {
eval "$(utools_local)"
local autoconfdir sitesdir onesite
parse_opts "${PRETTYOPTS[@]}" \
--sitesdir: sitesdir= \
--one-site: onesite= \
@ args -- "$@" && set -- "${args[@]}" || die "$args"
__apache_autoconf_setup || return 1
# Configuration
autoconfdir="$1"; shift
[ -n "$autoconfdir" ] || {
eerror "Vous devez spécifier le répertoire de base de la configuration apache"
return 1
}
[ -n "$sitesdir" ] || sitesdir="$autoconfdir/sites"
# Faire un script sed pour remplacer les variables spécifiées par leur
# valeur dans les fichiers
local -a FILLVARS; local FILLSCRIPT FILLTEMP ULIB_INSTALL_VERBOSE
__apache_autoconf_fillxxx
local -a newhosts
if [ -d "$sitesdir" ]; then
local -a localips localhosts confs candidates newhosts
local conf tmpconf candidate
array_from_lines localips "$(</etc/hosts awk '$1 ~ /127\./ { print $1 }' | sort -u)"
array_from_lines localhosts "$(</etc/hosts awk '$1 ~ /127\./ { for (i = 2; i <= NF; i++) { if ($i ~ /\.local$/) print $i } }' | sort -u)"
ac_set_tmpfile tmpconf
array_lsfiles confs "$sitesdir" "*.conf"
for conf in "${confs[@]}"; do
confname="$(basename "$conf")"
[ -z "$onesite" -o "$confname" == "$onesite" ] || continue
__apache_autoconf_fillcopy "$conf" "$tmpconf"
array_from_lines candidates "$(<"$tmpconf" awk '
$1 == "ServerName" && $2 ~ /\.local$/ { print $2 }
$1 == "ServerAlias" { for (i = 2; i <= NF; i++) { if ($i ~ /\.local$/) print $i } }
')"
for candidate in "${candidates[@]}"; do
array_contains localhosts "$candidate" || array_addu newhosts "$candidate"
done
done
fi
local ip host i=0
for host in "${newhosts[@]}"; do
i=$(($i + 1)); ip="127.0.1.$i"
while array_contains localips "$ip"; do
i=$(($i + 1)); ip="127.0.1.$i"
done
estep "Ajout de $ip $host"
echo "$ip $host" >>/etc/hosts
done
}