mirror of
https://github.com/openwrt/packages.git
synced 2025-12-22 01:44:32 +04:00
For runs started interactively, improve messaging and allow a run to be aborted with `service acme abort`. Signed-off-by: Aditya Bhargava <rightaditya@gmail.com>
219 lines
5.3 KiB
Bash
219 lines
5.3 KiB
Bash
#!/bin/sh
|
|
set -u
|
|
ACME=/usr/lib/acme/client/acme.sh
|
|
LOG_TAG=acme-acmesh
|
|
NOTIFY=/usr/lib/acme/notify
|
|
|
|
# shellcheck source=net/acme/files/functions.sh
|
|
. /usr/lib/acme/functions.sh
|
|
|
|
# Needed by acme.sh
|
|
export CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
|
|
export NO_TIMESTAMP=1
|
|
|
|
link_certs() {
|
|
local main_domain
|
|
local domain_dir
|
|
domain_dir="$1"
|
|
main_domain="$2"
|
|
|
|
(
|
|
umask 077
|
|
cat "$domain_dir/fullchain.cer" "$domain_dir/$main_domain.key" >"$domain_dir/combined.cer"
|
|
)
|
|
|
|
if [ ! -e "$CERT_DIR/$main_domain.crt" ]; then
|
|
ln -s "$domain_dir/$main_domain.cer" "$CERT_DIR/$main_domain.crt"
|
|
fi
|
|
if [ ! -e "$CERT_DIR/$main_domain.key" ]; then
|
|
ln -s "$domain_dir/$main_domain.key" "$CERT_DIR/$main_domain.key"
|
|
fi
|
|
if [ ! -e "$CERT_DIR/$main_domain.fullchain.crt" ]; then
|
|
ln -s "$domain_dir/fullchain.cer" "$CERT_DIR/$main_domain.fullchain.crt"
|
|
fi
|
|
if [ ! -e "$CERT_DIR/$main_domain.combined.crt" ]; then
|
|
ln -s "$domain_dir/combined.cer" "$CERT_DIR/$main_domain.combined.crt"
|
|
fi
|
|
if [ ! -e "$CERT_DIR/$main_domain.chain.crt" ]; then
|
|
ln -s "$domain_dir/ca.cer" "$CERT_DIR/$main_domain.chain.crt"
|
|
fi
|
|
}
|
|
|
|
handle_signal() {
|
|
local notify_op=$1
|
|
local label_op=$2
|
|
wait_notify() {
|
|
# wait for acme.sh child job to die, *then* notify about status
|
|
wait
|
|
log warn "$label_op aborted: $main_domain"
|
|
$NOTIFY "${notify_op}-failed"
|
|
exit 1
|
|
}
|
|
|
|
trap wait_notify TERM
|
|
# try to kill the cgroup
|
|
local cgroup=$(cut -d : -f 3 /proc/$$/cgroup)
|
|
if [[ "$cgroup" == '/services/acme/*' ]]; then
|
|
# send SIGTERM to all processes in this process's cgroup. this
|
|
# relies on procd's having set up the cgroup for the instance.
|
|
read -r -d '' pids < /sys/fs/cgroup${cgroup}/cgroup.procs
|
|
kill -TERM $pids 2> /dev/null
|
|
fi
|
|
|
|
# if we're here, either the cgroup wasn't as exected to be set up by
|
|
# procd or killing the cgroup PIDs failed. try to kill the process
|
|
# group, assuming this process is the group leader. this is actually
|
|
# unlikely since procd doesn't set service PGIDs (so they aren't group
|
|
# leaders).
|
|
kill -TERM -$$ 2> /dev/null
|
|
|
|
# if we're here, cgroup-based killing was avoided or didn't work and
|
|
# PGID-based killing didn't work. fall back to the raciest option.
|
|
trap "" TERM
|
|
term_descendants() {
|
|
local pids=$@
|
|
local pid=
|
|
# `pgrep -P` returns nothing if given a non-existent PID
|
|
# (even if the PID has live children), so children must
|
|
# be killed first
|
|
for pid in $pids; do
|
|
term_descendants $(pgrep -P "$pid")
|
|
kill -TERM "$pid" 2> /dev/null
|
|
done
|
|
}
|
|
term_descendants $(jobs -p)
|
|
|
|
wait_notify
|
|
}
|
|
|
|
case $1 in
|
|
get)
|
|
set --
|
|
[ "$debug" = 1 ] && set -- "$@" --debug
|
|
|
|
case $key_type in
|
|
ec*)
|
|
keylength=${key_type/ec/ec-}
|
|
domain_dir="$state_dir/${main_domain}_ecc"
|
|
set -- "$@" --ecc
|
|
;;
|
|
rsa*)
|
|
keylength=${key_type#rsa}
|
|
domain_dir="$state_dir/$main_domain"
|
|
;;
|
|
esac
|
|
|
|
log info "Running ACME for $main_domain with validation_method $validation_method"
|
|
|
|
staging_moved=0
|
|
if [ -e "$domain_dir" ]; then
|
|
if [ "$staging" = 0 ] && grep -q "acme-staging" "$domain_dir/$main_domain.conf"; then
|
|
mv "$domain_dir" "$domain_dir.staging"
|
|
log info "Certificates are previously issued from a staging server, but staging option is disabled, moved to $domain_dir.staging."
|
|
staging_moved=1
|
|
else
|
|
set -- "$@" --renew --home "$state_dir" -d "$main_domain"
|
|
log info "$ACME $*"
|
|
trap "handle_signal renew Renewal" INT TERM
|
|
$ACME "$@" &
|
|
wait $!
|
|
status=$?
|
|
trap - INT TERM
|
|
|
|
case $status in
|
|
0)
|
|
link_certs "$domain_dir" "$main_domain"
|
|
$NOTIFY renewed
|
|
exit
|
|
;;
|
|
2)
|
|
# renew skipped, ignore.
|
|
exit
|
|
;;
|
|
*)
|
|
$NOTIFY renew-failed
|
|
exit 1
|
|
;;
|
|
esac
|
|
fi
|
|
fi
|
|
|
|
for d in $domains; do
|
|
set -- "$@" -d "$d"
|
|
done
|
|
set -- "$@" --keylength "$keylength" --accountemail "$account_email"
|
|
|
|
if [ "$acme_server" ]; then
|
|
set -- "$@" --server "$acme_server"
|
|
# default to letsencrypt because the upstream default may change
|
|
elif [ "$staging" = 1 ]; then
|
|
set -- "$@" --server letsencrypt_test
|
|
else
|
|
set -- "$@" --server letsencrypt
|
|
fi
|
|
|
|
if [ "$days" ]; then
|
|
set -- "$@" --days "$days"
|
|
fi
|
|
|
|
case "$validation_method" in
|
|
"dns")
|
|
set -- "$@" --dns "$dns"
|
|
if [ "$dalias" ]; then
|
|
set -- "$@" --domain-alias "$dalias"
|
|
if [ "$calias" ]; then
|
|
log err "Both domain and challenge aliases are defined. Ignoring the challenge alias."
|
|
fi
|
|
elif [ "$calias" ]; then
|
|
set -- "$@" --challenge-alias "$calias"
|
|
fi
|
|
if [ "$dns_wait" ]; then
|
|
set -- "$@" --dnssleep "$dns_wait"
|
|
fi
|
|
;;
|
|
"standalone")
|
|
set -- "$@" --standalone --listen-v6 --httpport "$listen_port"
|
|
;;
|
|
"alpn")
|
|
set -- "$@" --alpn --listen-v6 --tlsport "$listen_port"
|
|
;;
|
|
"webroot")
|
|
mkdir -p "$CHALLENGE_DIR"
|
|
set -- "$@" --webroot "$CHALLENGE_DIR"
|
|
;;
|
|
*)
|
|
log err "Unsupported validation_method $validation_method"
|
|
;;
|
|
esac
|
|
|
|
set -- "$@" --issue --home "$state_dir"
|
|
|
|
log info "$ACME $*"
|
|
trap "handle_signal issue Issuance" INT TERM
|
|
"$ACME" "$@" \
|
|
--pre-hook "$NOTIFY prepare" \
|
|
--renew-hook "$NOTIFY renewed" &
|
|
wait $!
|
|
status=$?
|
|
trap - INT TERM
|
|
|
|
case $status in
|
|
0)
|
|
link_certs "$domain_dir" "$main_domain"
|
|
$NOTIFY issued
|
|
;;
|
|
*)
|
|
if [ "$staging_moved" = 1 ]; then
|
|
mv "$domain_dir.staging" "$domain_dir"
|
|
log err "Staging certificate restored"
|
|
elif [ -d "$domain_dir" ]; then
|
|
failed_dir="$domain_dir.failed-$(date +%s)"
|
|
mv "$domain_dir" "$failed_dir"
|
|
log err "State moved to $failed_dir"
|
|
fi
|
|
$NOTIFY issue-failed
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|