94fd62426235607ef3d84af220947ca5d94bc5cd
[librecmc/package-feed.git] / net / acme / files / run.sh
1 #!/bin/sh
2 # Wrapper for acme.sh to work on openwrt.
3 #
4 # This program is free software; you can redistribute it and/or modify it under
5 # the terms of the GNU General Public License as published by the Free Software
6 # Foundation; either version 3 of the License, or (at your option) any later
7 # version.
8 #
9 # Author: Toke Høiland-Jørgensen <toke@toke.dk>
10
11 CHECK_CRON=$1
12 ACME=/usr/lib/acme/acme.sh
13 export SSL_CERT_DIR=/etc/ssl/certs
14 export NO_TIMESTAMP=1
15
16 UHTTPD_LISTEN_HTTP=
17 STATE_DIR='/etc/acme'
18 ACCOUNT_EMAIL=
19 DEBUG=0
20
21 . /lib/functions.sh
22
23 check_cron()
24 {
25     [ -f "/etc/crontabs/root" ] && grep -q '/etc/init.d/acme' /etc/crontabs/root && return
26     echo "0 0 * * * /etc/init.d/acme start" >> /etc/crontabs/root
27     /etc/init.d/cron start
28 }
29
30 debug()
31 {
32     [ "$DEBUG" -eq "1" ] && echo "$@" >&2
33 }
34
35 pre_checks()
36 {
37     echo "Running pre checks."
38     check_cron
39
40     [ -d "$STATE_DIR" ] || mkdir -p "$STATE_DIR"
41
42     if [ -e /etc/init.d/uhttpd ]; then
43
44        UHTTPD_LISTEN_HTTP=$(uci get uhttpd.main.listen_http)
45
46        uci set uhttpd.main.listen_http=''
47        uci commit uhttpd
48        /etc/init.d/uhttpd reload || return 1
49     fi
50
51     iptables -I input_rule -p tcp --dport 80 -j ACCEPT || return 1
52     ip6tables -I input_rule -p tcp --dport 80 -j ACCEPT || return 1
53     debug "v4 input_rule: $(iptables -nvL input_rule)"
54     debug "v6 input_rule: $(ip6tables -nvL input_rule)"
55     debug "port80 listens: $(netstat -ntpl | grep :80)"
56     return 0
57 }
58
59 post_checks()
60 {
61     echo "Running post checks (cleanup)."
62     iptables -D input_rule -p tcp --dport 80 -j ACCEPT
63     ip6tables -D input_rule -p tcp --dport 80 -j ACCEPT
64
65     if [ -e /etc/init.d/uhttpd ]; then
66         uci set uhttpd.main.listen_http="$UHTTPD_LISTEN_HTTP"
67         uci commit uhttpd
68         /etc/init.d/uhttpd reload
69     fi
70 }
71
72 err_out()
73 {
74     post_checks
75     exit 1
76 }
77
78 int_out()
79 {
80     post_checks
81     trap - INT
82     kill -INT $$
83 }
84
85 is_staging()
86 {
87     local main_domain="$1"
88
89     grep -q "acme-staging" "$STATE_DIR/$main_domain/${main_domain}.conf"
90     return $?
91 }
92
93 issue_cert()
94 {
95     local section="$1"
96     local acme_args=
97     local enabled
98     local use_staging
99     local update_uhttpd
100     local keylength
101     local domains
102     local main_domain
103     local moved_staging=0
104     local failed_dir
105
106     config_get_bool enabled "$section" enabled 0
107     config_get_bool use_staging "$section" use_staging
108     config_get_bool update_uhttpd "$section" update_uhttpd
109     config_get domains "$section" domains
110     config_get keylength "$section" keylength
111
112     [ "$enabled" -eq "1" ] || return
113
114     [ "$DEBUG" -eq "1" ] && acme_args="$acme_args --debug"
115
116     set -- $domains
117     main_domain=$1
118
119     if [ -e "$STATE_DIR/$main_domain" ]; then
120         if [ "$use_staging" -eq "0" ] && is_staging "$main_domain"; then
121             echo "Found previous cert issued using staging server. Moving it out of the way."
122             mv "$STATE_DIR/$main_domain" "$STATE_DIR/$main_domain.staging"
123             moved_staging=1
124         else
125             echo "Found previous cert config. Issuing renew."
126             $ACME --home "$STATE_DIR" --renew -d "$main_domain" $acme_args || return 1
127             return 0
128         fi
129     fi
130
131
132     acme_args="$acme_args $(for d in $domains; do echo -n "-d $d "; done)"
133     acme_args="$acme_args --standalone"
134     acme_args="$acme_args --keylength $keylength"
135     [ -n "$ACCOUNT_EMAIL" ] && acme_args="$acme_args --accountemail $ACCOUNT_EMAIL"
136     [ "$use_staging" -eq "1" ] && acme_args="$acme_args --staging"
137
138     if ! $ACME --home "$STATE_DIR" --issue $acme_args; then
139         failed_dir="$STATE_DIR/${main_domain}.failed-$(date +%s)"
140         echo "Issuing cert for $main_domain failed. Moving state to $failed_dir" >&2
141         [ -d "$STATE_DIR/$main_domain" ] && mv "$STATE_DIR/$main_domain" "$failed_dir"
142         if [ "$moved_staging" -eq "1" ]; then
143             echo "Restoring staging certificate" >&2
144             mv "$STATE_DIR/${main_domain}.staging" "$STATE_DIR/${main_domain}"
145         fi
146         return 1
147     fi
148
149     if [ "$update_uhttpd" -eq "1" ]; then
150         uci set uhttpd.main.key="$STATE_DIR/${main_domain}/${main_domain}.key"
151         uci set uhttpd.main.cert="$STATE_DIR/${main_domain}/fullchain.cer"
152         # commit and reload is in post_checks
153     fi
154
155 }
156
157 load_vars()
158 {
159     local section="$1"
160
161     STATE_DIR=$(config_get "$section" state_dir)
162     ACCOUNT_EMAIL=$(config_get "$section" account_email)
163     DEBUG=$(config_get "$section" debug)
164 }
165
166 if [ -n "$CHECK_CRON" ]; then
167     check_cron
168     exit 0
169 fi
170
171 config_load acme
172 config_foreach load_vars acme
173
174 pre_checks || exit 1
175 trap err_out HUP TERM
176 trap int_out INT
177
178 config_foreach issue_cert cert
179 post_checks
180
181 exit 0