Browse Source

Merge remote-tracking branch 'upstream/master' into ssh-deploy

dnsconf
David Kerr 8 years ago
parent
commit
b30c1daf72
  1. 6
      .travis.yml
  2. 2
      README.md
  3. 240
      acme.sh
  4. 53
      deploy/README.md
  5. 2
      deploy/apache.sh
  6. 92
      deploy/exim4.sh
  7. 88
      deploy/vsftpd.sh
  8. 26
      dnsapi/README.md
  9. 148
      dnsapi/dns_do.sh
  10. 123
      dnsapi/dns_gandi_livedns.sh
  11. 31
      dnsapi/dns_lua.sh
  12. 31
      dnsapi/dns_me.sh

6
.travis.yml

@ -26,9 +26,9 @@ install:
_old_path="$PATH"; _old_path="$PATH";
echo "PATH=$PATH"; echo "PATH=$PATH";
export PATH=""; export PATH="";
export OPENSSL_BIN="/usr/local/openssl";
export ACME_OPENSSL_BIN="/usr/local/openssl";
openssl version 2>&1 || true; openssl version 2>&1 || true;
$OPENSSL_BIN version 2>&1 || true;
$ACME_OPENSSL_BIN version 2>&1 || true;
export PATH="$_old_path"; export PATH="$_old_path";
fi fi
@ -44,7 +44,7 @@ script:
- cd .. - cd ..
- git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi
- if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi
- if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi
matrix: matrix:

2
README.md

@ -293,6 +293,8 @@ You don't have to do anything manually!
1. Linode.com API 1. Linode.com API
1. FreeDNS (https://freedns.afraid.org/) 1. FreeDNS (https://freedns.afraid.org/)
1. cyon.ch 1. cyon.ch
1. Domain-Offensive/Resellerinterface/Domainrobot API
1. Gandi LiveDNS API
**More APIs coming soon...** **More APIs coming soon...**

240
acme.sh

@ -137,16 +137,16 @@ _printargs() {
_dlg_versions() { _dlg_versions() {
echo "Diagnosis versions: " echo "Diagnosis versions: "
echo "openssl:$OPENSSL_BIN"
if _exists "$OPENSSL_BIN"; then
$OPENSSL_BIN version 2>&1
echo "openssl:$ACME_OPENSSL_BIN"
if _exists "$ACME_OPENSSL_BIN"; then
$ACME_OPENSSL_BIN version 2>&1
else else
echo "$OPENSSL_BIN doesn't exists."
echo "$ACME_OPENSSL_BIN doesn't exists."
fi fi
echo "apache:" echo "apache:"
if [ "$_APACHECTL" ] && _exists "$_APACHECTL"; then if [ "$_APACHECTL" ] && _exists "$_APACHECTL"; then
_APACHECTL -V 2>&1
$_APACHECTL -V 2>&1
else else
echo "apache doesn't exists." echo "apache doesn't exists."
fi fi
@ -780,19 +780,19 @@ _base64() {
[ "" ] #urgly [ "" ] #urgly
if [ "$1" ]; then if [ "$1" ]; then
_debug3 "base64 multiline:'$1'" _debug3 "base64 multiline:'$1'"
$OPENSSL_BIN base64 -e
$ACME_OPENSSL_BIN base64 -e
else else
_debug3 "base64 single line." _debug3 "base64 single line."
$OPENSSL_BIN base64 -e | tr -d '\r\n'
$ACME_OPENSSL_BIN base64 -e | tr -d '\r\n'
fi fi
} }
#Usage: multiline #Usage: multiline
_dbase64() { _dbase64() {
if [ "$1" ]; then if [ "$1" ]; then
$OPENSSL_BIN base64 -d -A
$ACME_OPENSSL_BIN base64 -d -A
else else
$OPENSSL_BIN base64 -d
$ACME_OPENSSL_BIN base64 -d
fi fi
} }
@ -809,9 +809,9 @@ _digest() {
if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then
if [ "$outputhex" ]; then if [ "$outputhex" ]; then
$OPENSSL_BIN dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' '
$ACME_OPENSSL_BIN dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' '
else else
$OPENSSL_BIN dgst -"$alg" -binary | _base64
$ACME_OPENSSL_BIN dgst -"$alg" -binary | _base64
fi fi
else else
_err "$alg is not supported yet" _err "$alg is not supported yet"
@ -834,9 +834,9 @@ _hmac() {
if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then
if [ "$outputhex" ]; then if [ "$outputhex" ]; then
($OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || $OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' '
($ACME_OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || $ACME_OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' '
else else
$OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || $OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary
$ACME_OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || $ACME_OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary
fi fi
else else
_err "$alg is not supported yet" _err "$alg is not supported yet"
@ -855,7 +855,7 @@ _sign() {
return 1 return 1
fi fi
_sign_openssl="$OPENSSL_BIN dgst -sign $keyfile "
_sign_openssl="$ACME_OPENSSL_BIN dgst -sign $keyfile "
if [ "$alg" = "sha256" ]; then if [ "$alg" = "sha256" ]; then
_sign_openssl="$_sign_openssl -$alg" _sign_openssl="$_sign_openssl -$alg"
else else
@ -866,7 +866,7 @@ _sign() {
if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
$_sign_openssl | _base64 $_sign_openssl | _base64
elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
if ! _signedECText="$($_sign_openssl | $OPENSSL_BIN asn1parse -inform DER)"; then
if ! _signedECText="$($_sign_openssl | $ACME_OPENSSL_BIN asn1parse -inform DER)"; then
_err "Sign failed: $_sign_openssl" _err "Sign failed: $_sign_openssl"
_err "Key file: $keyfile" _err "Key file: $keyfile"
_err "Key content:$(wc -l <"$keyfile") lises" _err "Key content:$(wc -l <"$keyfile") lises"
@ -927,12 +927,21 @@ _createkey() {
_debug "Use length $length" _debug "Use length $length"
if ! touch "$f" >/dev/null 2>&1; then
_f_path="$(dirname "$f")"
_debug _f_path "$_f_path"
if ! mkdir -p "$_f_path"; then
_err "Can not create path: $_f_path"
return 1
fi
fi
if _isEccKey "$length"; then if _isEccKey "$length"; then
_debug "Using ec name: $eccname" _debug "Using ec name: $eccname"
$OPENSSL_BIN ecparam -name "$eccname" -genkey 2>/dev/null >"$f"
$ACME_OPENSSL_BIN ecparam -name "$eccname" -genkey 2>/dev/null >"$f"
else else
_debug "Using RSA: $length" _debug "Using RSA: $length"
$OPENSSL_BIN genrsa "$length" 2>/dev/null >"$f"
$ACME_OPENSSL_BIN genrsa "$length" 2>/dev/null >"$f"
fi fi
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
@ -1019,9 +1028,9 @@ _createcsr() {
_csr_cn="$(_idn "$domain")" _csr_cn="$(_idn "$domain")"
_debug2 _csr_cn "$_csr_cn" _debug2 _csr_cn "$_csr_cn"
if _contains "$(uname -a)" "MINGW"; then if _contains "$(uname -a)" "MINGW"; then
$OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr"
$ACME_OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr"
else else
$OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr"
$ACME_OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr"
fi fi
} }
@ -1033,7 +1042,7 @@ _signcsr() {
cert="$4" cert="$4"
_debug "_signcsr" _debug "_signcsr"
_msg="$($OPENSSL_BIN x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)"
_msg="$($ACME_OPENSSL_BIN x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)"
_ret="$?" _ret="$?"
_debug "$_msg" _debug "$_msg"
return $_ret return $_ret
@ -1046,7 +1055,7 @@ _readSubjectFromCSR() {
_usage "_readSubjectFromCSR mycsr.csr" _usage "_readSubjectFromCSR mycsr.csr"
return 1 return 1
fi fi
$OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n'
$ACME_OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n'
} }
#_csrfile #_csrfile
@ -1061,7 +1070,7 @@ _readSubjectAltNamesFromCSR() {
_csrsubj="$(_readSubjectFromCSR "$_csrfile")" _csrsubj="$(_readSubjectFromCSR "$_csrfile")"
_debug _csrsubj "$_csrsubj" _debug _csrsubj "$_csrsubj"
_dnsAltnames="$($OPENSSL_BIN req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')"
_dnsAltnames="$($ACME_OPENSSL_BIN req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')"
_debug _dnsAltnames "$_dnsAltnames" _debug _dnsAltnames "$_dnsAltnames"
if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then
@ -1082,7 +1091,7 @@ _readKeyLengthFromCSR() {
return 1 return 1
fi fi
_outcsr="$($OPENSSL_BIN req -noout -text -in "$_csrfile")"
_outcsr="$($ACME_OPENSSL_BIN req -noout -text -in "$_csrfile")"
if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then
_debug "ECC CSR" _debug "ECC CSR"
echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' '
@ -1136,9 +1145,9 @@ toPkcs() {
_initpath "$domain" "$_isEcc" _initpath "$domain" "$_isEcc"
if [ "$pfxPassword" ]; then if [ "$pfxPassword" ]; then
$OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword"
$ACME_OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword"
else else
$OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH"
$ACME_OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH"
fi fi
if [ "$?" = "0" ]; then if [ "$?" = "0" ]; then
@ -1147,6 +1156,27 @@ toPkcs() {
} }
#domain [isEcc]
toPkcs8() {
domain="$1"
if [ -z "$domain" ]; then
_usage "Usage: $PROJECT_ENTRY --toPkcs8 -d domain [--ecc]"
return 1
fi
_isEcc="$2"
_initpath "$domain" "$_isEcc"
$ACME_OPENSSL_BIN pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in "$CERT_KEY_PATH" -out "$CERT_PKCS8_PATH"
if [ "$?" = "0" ]; then
_info "Success, $CERT_PKCS8_PATH"
fi
}
#[2048] #[2048]
createAccountKey() { createAccountKey() {
_info "Creating account key" _info "Creating account key"
@ -1249,12 +1279,12 @@ _url_replace() {
} }
_time2str() { _time2str() {
#BSD
#Linux
if date -u -d@"$1" 2>/dev/null; then if date -u -d@"$1" 2>/dev/null; then
return return
fi fi
#Linux
#BSD
if date -u -r "$1" 2>/dev/null; then if date -u -r "$1" 2>/dev/null; then
return return
fi fi
@ -1300,7 +1330,7 @@ _calcjwk() {
if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
_debug "RSA key" _debug "RSA key"
pub_exp=$($OPENSSL_BIN rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1)
pub_exp=$($ACME_OPENSSL_BIN rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1)
if [ "${#pub_exp}" = "5" ]; then if [ "${#pub_exp}" = "5" ]; then
pub_exp=0$pub_exp pub_exp=0$pub_exp
fi fi
@ -1309,7 +1339,7 @@ _calcjwk() {
e=$(echo "$pub_exp" | _h2b | _base64) e=$(echo "$pub_exp" | _h2b | _base64)
_debug3 e "$e" _debug3 e "$e"
modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2)
modulus=$($ACME_OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2)
_debug3 modulus "$modulus" _debug3 modulus "$modulus"
n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)" n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)"
_debug3 n "$n" _debug3 n "$n"
@ -1322,12 +1352,12 @@ _calcjwk() {
JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}'
elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
_debug "EC key" _debug "EC key"
crv="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")"
crv="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")"
_debug3 crv "$crv" _debug3 crv "$crv"
if [ -z "$crv" ]; then if [ -z "$crv" ]; then
_debug "Let's try ASN1 OID" _debug "Let's try ASN1 OID"
crv_oid="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")"
crv_oid="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")"
_debug3 crv_oid "$crv_oid" _debug3 crv_oid "$crv_oid"
case "${crv_oid}" in case "${crv_oid}" in
"prime256v1") "prime256v1")
@ -1347,15 +1377,15 @@ _calcjwk() {
_debug3 crv "$crv" _debug3 crv "$crv"
fi fi
pubi="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)"
pubi="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)"
pubi=$(_math "$pubi" + 1) pubi=$(_math "$pubi" + 1)
_debug3 pubi "$pubi" _debug3 pubi "$pubi"
pubj="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)"
pubj="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)"
pubj=$(_math "$pubj" - 1) pubj=$(_math "$pubj" - 1)
_debug3 pubj "$pubj" _debug3 pubj "$pubj"
pubtext="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")"
pubtext="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")"
_debug3 pubtext "$pubtext" _debug3 pubtext "$pubtext"
xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)" xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)"
@ -1455,6 +1485,11 @@ _inithttp() {
fi fi
fi fi
#from wget 1.14: do not skip body on 404 error
if [ "$_ACME_WGET" ] && _contains "$($_ACME_WGET --help 2>&1)" "--content-on-error"; then
_ACME_WGET="$_ACME_WGET --content-on-error "
fi
__HTTP_INITIALIZED=1 __HTTP_INITIALIZED=1
} }
@ -1475,7 +1510,7 @@ _post() {
_inithttp _inithttp
if [ "$_ACME_CURL" ]; then
if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then
_CURL="$_ACME_CURL" _CURL="$_ACME_CURL"
if [ "$HTTPS_INSECURE" ]; then if [ "$HTTPS_INSECURE" ]; then
_CURL="$_CURL --insecure " _CURL="$_CURL --insecure "
@ -1516,7 +1551,7 @@ _post() {
_ret="$?" _ret="$?"
if [ "$_ret" = "8" ]; then if [ "$_ret" = "8" ]; then
_ret=0 _ret=0
_debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later."
_debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
fi fi
if [ "$_ret" != "0" ]; then if [ "$_ret" != "0" ]; then
_err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret" _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret"
@ -1542,7 +1577,7 @@ _get() {
_inithttp _inithttp
if [ "$_ACME_CURL" ]; then
if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then
_CURL="$_ACME_CURL" _CURL="$_ACME_CURL"
if [ "$HTTPS_INSECURE" ]; then if [ "$HTTPS_INSECURE" ]; then
_CURL="$_CURL --insecure " _CURL="$_CURL --insecure "
@ -1579,9 +1614,9 @@ _get() {
$_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - "$url" $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - "$url"
fi fi
ret=$? ret=$?
if [ "$_ret" = "8" ]; then
_ret=0
_debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later."
if [ "$ret" = "8" ]; then
ret=0
_debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
fi fi
if [ "$ret" != "0" ]; then if [ "$ret" != "0" ]; then
_err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret" _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret"
@ -1964,7 +1999,7 @@ _starttlsserver() {
return 1 return 1
fi fi
__S_OPENSSL="$OPENSSL_BIN s_server -cert $TLS_CERT -key $TLS_KEY "
__S_OPENSSL="$ACME_OPENSSL_BIN s_server -cert $TLS_CERT -key $TLS_KEY "
if [ "$opaddr" ]; then if [ "$opaddr" ]; then
__S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port"
else else
@ -2143,8 +2178,8 @@ _initpath() {
CERT_HOME="$_DEFAULT_CERT_HOME" CERT_HOME="$_DEFAULT_CERT_HOME"
fi fi
if [ -z "$OPENSSL_BIN" ]; then
OPENSSL_BIN="$DEFAULT_OPENSSL_BIN"
if [ -z "$ACME_OPENSSL_BIN" ] || [ ! -f "$ACME_OPENSSL_BIN" ] || [ ! -x "$ACME_OPENSSL_BIN" ]; then
ACME_OPENSSL_BIN="$DEFAULT_OPENSSL_BIN"
fi fi
if [ -z "$1" ]; then if [ -z "$1" ]; then
@ -2200,6 +2235,9 @@ _initpath() {
if [ -z "$CERT_PFX_PATH" ]; then if [ -z "$CERT_PFX_PATH" ]; then
CERT_PFX_PATH="$DOMAIN_PATH/$domain.pfx" CERT_PFX_PATH="$DOMAIN_PATH/$domain.pfx"
fi fi
if [ -z "$CERT_PKCS8_PATH" ]; then
CERT_PKCS8_PATH="$DOMAIN_PATH/$domain.pkcs8"
fi
if [ -z "$TLS_CONF" ]; then if [ -z "$TLS_CONF" ]; then
TLS_CONF="$DOMAIN_PATH/tls.valdation.conf" TLS_CONF="$DOMAIN_PATH/tls.valdation.conf"
@ -2795,6 +2833,7 @@ _on_before_issue() {
_on_issue_err() { _on_issue_err() {
_chk_post_hook="$1" _chk_post_hook="$1"
_chk_vlist="$2"
_debug _on_issue_err _debug _on_issue_err
if [ "$LOG_FILE" ]; then if [ "$LOG_FILE" ]; then
_err "Please check log file for more details: $LOG_FILE" _err "Please check log file for more details: $LOG_FILE"
@ -2803,10 +2842,6 @@ _on_issue_err() {
_err "See: $_DEBUG_WIKI" _err "See: $_DEBUG_WIKI"
fi fi
if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then
_debug "$(_dlg_versions)"
fi
#run the post hook #run the post hook
if [ "$_chk_post_hook" ]; then if [ "$_chk_post_hook" ]; then
_info "Run post hook:'$_chk_post_hook'" _info "Run post hook:'$_chk_post_hook'"
@ -2817,6 +2852,28 @@ _on_issue_err() {
return 1 return 1
fi fi
fi fi
#trigger the validation to flush the pending authz
if [ "$_chk_vlist" ]; then
(
_debug2 "_chk_vlist" "$_chk_vlist"
_debug2 "start to deactivate authz"
ventries=$(echo "$_chk_vlist" | tr "$dvsep" ' ')
for ventry in $ventries; do
d=$(echo "$ventry" | cut -d "$sep" -f 1)
keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
uri=$(echo "$ventry" | cut -d "$sep" -f 3)
vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
_currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
__trigger_validaton "$uri" "$keyauthorization"
done
)
fi
if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then
_debug "$(_dlg_versions)"
fi
} }
_on_issue_success() { _on_issue_success() {
@ -3029,6 +3086,16 @@ __get_domain_new_authz() {
} }
#uri keyAuthorization
__trigger_validaton() {
_debug2 "tigger domain validation."
_t_url="$1"
_debug2 _t_url "$_t_url"
_t_key_authz="$2"
_debug2 _t_key_authz "$_t_key_authz"
_send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}"
}
#webroot, domain domainlist keylength #webroot, domain domainlist keylength
issue() { issue() {
if [ -z "$2" ]; then if [ -z "$2" ]; then
@ -3342,7 +3409,7 @@ issue() {
_startserver "$keyauthorization" "$_ncaddr" & _startserver "$keyauthorization" "$_ncaddr" &
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
_clearup _clearup
_on_issue_err "$_post_hook"
_on_issue_err "$_post_hook" "$vlist"
return 1 return 1
fi fi
serverproc="$!" serverproc="$!"
@ -3358,7 +3425,7 @@ issue() {
BACKUP_NGINX_CONF="" BACKUP_NGINX_CONF=""
if ! _setNginx "$d" "$_currentRoot" "$thumbprint"; then if ! _setNginx "$d" "$_currentRoot" "$thumbprint"; then
_clearup _clearup
_on_issue_err "$_post_hook"
_on_issue_err "$_post_hook" "$vlist"
return 1 return 1
fi fi
@ -3393,7 +3460,7 @@ issue() {
_err "$d:Can not write token to file : $wellknown_path/$token" _err "$d:Can not write token to file : $wellknown_path/$token"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
_on_issue_err "$_post_hook"
_on_issue_err "$_post_hook" "$vlist"
return 1 return 1
fi fi
@ -3438,16 +3505,16 @@ issue() {
_err "Start tls server error." _err "Start tls server error."
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
_on_issue_err "$_post_hook"
_on_issue_err "$_post_hook" "$vlist"
return 1 return 1
fi fi
fi fi
if ! _send_signed_request "$uri" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}"; then
if ! __trigger_validaton "$uri" "$keyauthorization"; then
_err "$d:Can not get challenge: $response" _err "$d:Can not get challenge: $response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
_on_issue_err "$_post_hook"
_on_issue_err "$_post_hook" "$vlist"
return 1 return 1
fi fi
@ -3455,7 +3522,7 @@ issue() {
_err "$d:Challenge error: $response" _err "$d:Challenge error: $response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
_on_issue_err "$_post_hook"
_on_issue_err "$_post_hook" "$vlist"
return 1 return 1
fi fi
@ -3470,7 +3537,7 @@ issue() {
_err "$d:Timeout" _err "$d:Timeout"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
_on_issue_err
_on_issue_err "$_post_hook" "$vlist"
return 1 return 1
fi fi
@ -3482,7 +3549,7 @@ issue() {
_err "$d:Verify error:$response" _err "$d:Verify error:$response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
_on_issue_err "$_post_hook"
_on_issue_err "$_post_hook" "$vlist"
return 1 return 1
fi fi
_debug2 original "$response" _debug2 original "$response"
@ -3517,7 +3584,7 @@ issue() {
fi fi
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
_on_issue_err "$_post_hook"
_on_issue_err "$_post_hook" "$vlist"
return 1 return 1
fi fi
@ -3527,7 +3594,7 @@ issue() {
_err "$d:Verify error:$response" _err "$d:Verify error:$response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
_on_issue_err "$_post_hook"
_on_issue_err "$_post_hook" "$vlist"
return 1 return 1
fi fi
@ -3653,7 +3720,7 @@ issue() {
_savedomainconf "Le_RealKeyPath" "$_real_key" _savedomainconf "Le_RealKeyPath" "$_real_key"
_savedomainconf "Le_ReloadCmd" "$_reload_cmd" _savedomainconf "Le_ReloadCmd" "$_reload_cmd"
_savedomainconf "Le_RealFullChainPath" "$_real_fullchain" _savedomainconf "Le_RealFullChainPath" "$_real_fullchain"
_installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain"
_installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"
fi fi
} }
@ -3964,16 +4031,18 @@ installcert() {
_savedomainconf "Le_ReloadCmd" "$_reload_cmd" _savedomainconf "Le_ReloadCmd" "$_reload_cmd"
_savedomainconf "Le_RealFullChainPath" "$_real_fullchain" _savedomainconf "Le_RealFullChainPath" "$_real_fullchain"
_installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain"
_installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"
} }
#domain cert key ca fullchain reloadcmd backup-prefix
_installcert() { _installcert() {
_main_domain="$1" _main_domain="$1"
_real_cert="$2" _real_cert="$2"
_real_key="$3" _real_key="$3"
_real_ca="$4" _real_ca="$4"
_reload_cmd="$5"
_real_fullchain="$6"
_real_fullchain="$5"
_reload_cmd="$6"
_backup_prefix="$7"
if [ "$_real_cert" = "$NO_VALUE" ]; then if [ "$_real_cert" = "$NO_VALUE" ]; then
_real_cert="" _real_cert=""
@ -3991,11 +4060,13 @@ _installcert() {
_real_fullchain="" _real_fullchain=""
fi fi
_backup_path="$DOMAIN_BACKUP_PATH/$_backup_prefix"
mkdir -p "$_backup_path"
if [ "$_real_cert" ]; then if [ "$_real_cert" ]; then
_info "Installing cert to:$_real_cert" _info "Installing cert to:$_real_cert"
if [ -f "$_real_cert" ] && [ ! "$IS_RENEW" ]; then if [ -f "$_real_cert" ] && [ ! "$IS_RENEW" ]; then
mkdir -p "$DOMAIN_BACKUP_PATH"
cp "$_real_cert" "$DOMAIN_BACKUP_PATH/cert.bak"
cp "$_real_cert" "$_backup_path/cert.bak"
fi fi
cat "$CERT_PATH" >"$_real_cert" cat "$CERT_PATH" >"$_real_cert"
fi fi
@ -4007,8 +4078,7 @@ _installcert() {
cat "$CA_CERT_PATH" >>"$_real_ca" cat "$CA_CERT_PATH" >>"$_real_ca"
else else
if [ -f "$_real_ca" ] && [ ! "$IS_RENEW" ]; then if [ -f "$_real_ca" ] && [ ! "$IS_RENEW" ]; then
mkdir -p "$DOMAIN_BACKUP_PATH"
cp "$_real_ca" "$DOMAIN_BACKUP_PATH/ca.bak"
cp "$_real_ca" "$_backup_path/ca.bak"
fi fi
cat "$CA_CERT_PATH" >"$_real_ca" cat "$CA_CERT_PATH" >"$_real_ca"
fi fi
@ -4017,8 +4087,7 @@ _installcert() {
if [ "$_real_key" ]; then if [ "$_real_key" ]; then
_info "Installing key to:$_real_key" _info "Installing key to:$_real_key"
if [ -f "$_real_key" ] && [ ! "$IS_RENEW" ]; then if [ -f "$_real_key" ] && [ ! "$IS_RENEW" ]; then
mkdir -p "$DOMAIN_BACKUP_PATH"
cp "$_real_key" "$DOMAIN_BACKUP_PATH/key.bak"
cp "$_real_key" "$_backup_path/key.bak"
fi fi
cat "$CERT_KEY_PATH" >"$_real_key" cat "$CERT_KEY_PATH" >"$_real_key"
fi fi
@ -4026,8 +4095,7 @@ _installcert() {
if [ "$_real_fullchain" ]; then if [ "$_real_fullchain" ]; then
_info "Installing full chain to:$_real_fullchain" _info "Installing full chain to:$_real_fullchain"
if [ -f "$_real_fullchain" ] && [ ! "$IS_RENEW" ]; then if [ -f "$_real_fullchain" ] && [ ! "$IS_RENEW" ]; then
mkdir -p "$DOMAIN_BACKUP_PATH"
cp "$_real_fullchain" "$DOMAIN_BACKUP_PATH/fullchain.bak"
cp "$_real_fullchain" "$_backup_path/fullchain.bak"
fi fi
cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain"
fi fi
@ -4367,8 +4435,8 @@ _precheck() {
fi fi
fi fi
if ! _exists "$OPENSSL_BIN"; then
_err "Please install openssl first."
if ! _exists "$ACME_OPENSSL_BIN"; then
_err "Please install openssl first. ACME_OPENSSL_BIN=$ACME_OPENSSL_BIN"
_err "We need openssl to generate keys." _err "We need openssl to generate keys."
return 1 return 1
fi fi
@ -4660,6 +4728,7 @@ Commands:
--uninstall-cronjob Uninstall the cron job. The 'uninstall' command can do this automatically. --uninstall-cronjob Uninstall the cron job. The 'uninstall' command can do this automatically.
--cron Run cron job to renew all the certs. --cron Run cron job to renew all the certs.
--toPkcs Export the certificate and key to a pfx file. --toPkcs Export the certificate and key to a pfx file.
--toPkcs8 Convert to pkcs8 format.
--update-account Update account info. --update-account Update account info.
--register-account Register account key. --register-account Register account key.
--create-account-key Create an account private key, professional use. --create-account-key Create an account private key, professional use.
@ -4723,6 +4792,7 @@ Parameters:
--listen-v4 Force standalone/tls server to listen at ipv4. --listen-v4 Force standalone/tls server to listen at ipv4.
--listen-v6 Force standalone/tls server to listen at ipv6. --listen-v6 Force standalone/tls server to listen at ipv6.
--openssl-bin Specifies a custom openssl bin location. --openssl-bin Specifies a custom openssl bin location.
--use-wget Force to use wget, if you have both curl and wget installed.
" "
} }
@ -4790,9 +4860,9 @@ _processAccountConf() {
fi fi
if [ "$_openssl_bin" ]; then if [ "$_openssl_bin" ]; then
_saveaccountconf "OPENSSL_BIN" "$_openssl_bin"
elif [ "$OPENSSL_BIN" ] && [ "$OPENSSL_BIN" != "$DEFAULT_OPENSSL_BIN" ]; then
_saveaccountconf "OPENSSL_BIN" "$OPENSSL_BIN"
_saveaccountconf "ACME_OPENSSL_BIN" "$_openssl_bin"
elif [ "$ACME_OPENSSL_BIN" ] && [ "$ACME_OPENSSL_BIN" != "$DEFAULT_OPENSSL_BIN" ]; then
_saveaccountconf "ACME_OPENSSL_BIN" "$ACME_OPENSSL_BIN"
fi fi
if [ "$_auto_upgrade" ]; then if [ "$_auto_upgrade" ]; then
@ -4801,6 +4871,12 @@ _processAccountConf() {
_saveaccountconf "AUTO_UPGRADE" "$AUTO_UPGRADE" _saveaccountconf "AUTO_UPGRADE" "$AUTO_UPGRADE"
fi fi
if [ "$_use_wget" ]; then
_saveaccountconf "ACME_USE_WGET" "$_use_wget"
elif [ "$ACME_USE_WGET" ]; then
_saveaccountconf "ACME_USE_WGET" "$ACME_USE_WGET"
fi
} }
_process() { _process() {
@ -4845,6 +4921,7 @@ _process() {
_listen_v6="" _listen_v6=""
_openssl_bin="" _openssl_bin=""
_syslog="" _syslog=""
_use_wget=""
while [ ${#} -gt 0 ]; do while [ ${#} -gt 0 ]; do
case "${1}" in case "${1}" in
@ -4907,6 +4984,9 @@ _process() {
--toPkcs) --toPkcs)
_CMD="toPkcs" _CMD="toPkcs"
;; ;;
--toPkcs8)
_CMD="toPkcs8"
;;
--createAccountKey | --createaccountkey | -cak | --create-account-key) --createAccountKey | --createaccountkey | -cak | --create-account-key)
_CMD="createAccountKey" _CMD="createAccountKey"
;; ;;
@ -5218,7 +5298,12 @@ _process() {
;; ;;
--openssl-bin) --openssl-bin)
_openssl_bin="$2" _openssl_bin="$2"
OPENSSL_BIN="$_openssl_bin"
ACME_OPENSSL_BIN="$_openssl_bin"
shift
;;
--use-wget)
_use_wget="1"
ACME_USE_WGET="1"
;; ;;
*) *)
_err "Unknown parameter : $1" _err "Unknown parameter : $1"
@ -5319,6 +5404,9 @@ _process() {
toPkcs) toPkcs)
toPkcs "$_domain" "$_password" "$_ecc" toPkcs "$_domain" "$_password" "$_ecc"
;; ;;
toPkcs8)
toPkcs8 "$_domain" "$_ecc"
;;
createAccountKey) createAccountKey)
createAccountKey "$_accountkeylength" createAccountKey "$_accountkeylength"
;; ;;

53
deploy/README.md

@ -1,19 +1,21 @@
# Using deploy api # Using deploy api
Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert).
Here are the scripts to deploy the certs/key to the server/services. Here are the scripts to deploy the certs/key to the server/services.
## 1. Deploy the certs to your cpanel host. ## 1. Deploy the certs to your cpanel host.
(cpanel deploy hook is not finished yet, this is just an example.) (cpanel deploy hook is not finished yet, this is just an example.)
Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert).
Then you can deploy now: Then you can deploy now:
```sh ```sh
export DEPLOY_CPANEL_USER=myusername export DEPLOY_CPANEL_USER=myusername
export DEPLOY_CPANEL_PASSWORD=PASSWORD export DEPLOY_CPANEL_PASSWORD=PASSWORD
acme.sh --deploy -d example.com --deploy --deploy-hook cpanel
acme.sh --deploy -d example.com --deploy-hook cpanel
``` ```
## 2. Deploy ssl cert on kong proxy engine based on api. ## 2. Deploy ssl cert on kong proxy engine based on api.
@ -24,6 +26,8 @@ Before you can deploy your cert, you must [issue the cert first](https://github.
## 3. Deploy the cert to remote server through SSH access. ## 3. Deploy the cert to remote server through SSH access.
Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert).
The ssh deploy plugin allows you to deploy certificates to a remote host The ssh deploy plugin allows you to deploy certificates to a remote host
using SSH command to connect to the remote server. The ssh plugin is invoked using SSH command to connect to the remote server. The ssh plugin is invoked
with the following command... with the following command...
@ -107,7 +111,6 @@ user
Any backups older than 180 days will be deleted when new certificates Any backups older than 180 days will be deleted when new certificates
are deployed. This defaults to "yes" set to "no" to disable backup. are deployed. This defaults to "yes" set to "no" to disable backup.
###Eamples using SSH deploy ###Eamples using SSH deploy
The following example illustrates deploying certifcates to a QNAP NAS The following example illustrates deploying certifcates to a QNAP NAS
(tested with QTS version 4.2.3) (tested with QTS version 4.2.3)
@ -165,3 +168,47 @@ export DEPLOY_SSH_BACKUP=no
/var/lib/unifi/unifi.example.com.p12 \ /var/lib/unifi/unifi.example.com.p12 \
&& service unifi restart && service unifi restart
``` ```
## 4. Deploy the cert to local vsftpd server.
```sh
acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd
```
The default vsftpd conf file is `/etc/vsftpd.conf`, if your vsftpd conf is not in the default location, you can specify one:
```sh
export DEPLOY_VSFTPD_CONF="/etc/vsftpd.conf"
acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd
```
The default command to restart vsftpd server is `service vsftpd restart`, if it doesn't work, you can specify one:
```sh
export DEPLOY_VSFTPD_RELOAD="/etc/init.d/vsftpd restart"
acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd
```
## 5. Deploy the cert to local exim4 server.
```sh
acme.sh --deploy -d ftp.example.com --deploy-hook exim4
```
The default exim4 conf file is `/etc/exim/exim.conf`, if your exim4 conf is not in the default location, you can specify one:
```sh
export DEPLOY_EXIM4_CONF="/etc/exim4/exim4.conf.template"
acme.sh --deploy -d ftp.example.com --deploy-hook exim4
```
The default command to restart exim4 server is `service exim4 restart`, if it doesn't work, you can specify one:
```sh
export DEPLOY_EXIM4_RELOAD="/etc/init.d/exim4 restart"
acme.sh --deploy -d ftp.example.com --deploy-hook exim4
```

2
deploy/apache.sh

@ -1,6 +1,6 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#Here is a script to deploy cert to dovecot server.
#Here is a script to deploy cert to apache server.
#returns 0 means success, otherwise error. #returns 0 means success, otherwise error.

92
deploy/exim4.sh

@ -4,6 +4,9 @@
#returns 0 means success, otherwise error. #returns 0 means success, otherwise error.
#DEPLOY_EXIM4_CONF="/etc/exim/exim.conf"
#DEPLOY_EXIM4_RELOAD="service exim4 restart"
######## Public functions ##################### ######## Public functions #####################
#domain keyfile certfile cafile fullchain #domain keyfile certfile cafile fullchain
@ -20,7 +23,92 @@ exim4_deploy() {
_debug _cca "$_cca" _debug _cca "$_cca"
_debug _cfullchain "$_cfullchain" _debug _cfullchain "$_cfullchain"
_err "deploy cert to exim4 server, Not implemented yet"
return 1
_ssl_path="/etc/acme.sh/exim4"
if ! mkdir -p "$_ssl_path"; then
_err "Can not create folder:$_ssl_path"
return 1
fi
_info "Copying key and cert"
_real_key="$_ssl_path/exim4.key"
if ! cat "$_ckey" >"$_real_key"; then
_err "Error: write key file to: $_real_key"
return 1
fi
_real_fullchain="$_ssl_path/exim4.pem"
if ! cat "$_cfullchain" >"$_real_fullchain"; then
_err "Error: write key file to: $_real_fullchain"
return 1
fi
DEFAULT_EXIM4_RELOAD="service exim4 restart"
_reload="${DEPLOY_EXIM4_RELOAD:-$DEFAULT_EXIM4_RELOAD}"
if [ -z "$IS_RENEW" ]; then
DEFAULT_EXIM4_CONF="/etc/exim/exim.conf"
if [ ! -f "$DEFAULT_EXIM4_CONF" ]; then
DEFAULT_EXIM4_CONF="/etc/exim4/exim4.conf.template"
fi
_exim4_conf="${DEPLOY_EXIM4_CONF:-$DEFAULT_EXIM4_CONF}"
_debug _exim4_conf "$_exim4_conf"
if [ ! -f "$_exim4_conf" ]; then
if [ -z "$DEPLOY_EXIM4_CONF" ]; then
_err "exim4 conf is not found, please define DEPLOY_EXIM4_CONF"
return 1
else
_err "It seems that the specified exim4 conf is not valid, please check."
return 1
fi
fi
if [ ! -w "$_exim4_conf" ]; then
_err "The file $_exim4_conf is not writable, please change the permission."
return 1
fi
_backup_conf="$DOMAIN_BACKUP_PATH/exim4.conf.bak"
_info "Backup $_exim4_conf to $_backup_conf"
cp "$_exim4_conf" "$_backup_conf"
_info "Modify exim4 conf: $_exim4_conf"
if _setopt "$_exim4_conf" "tls_certificate" "=" "$_real_fullchain" \
&& _setopt "$_exim4_conf" "tls_privatekey" "=" "$_real_key"; then
_info "Set config success!"
else
_err "Config exim4 server error, please report bug to us."
_info "Restoring exim4 conf"
if cat "$_backup_conf" >"$_exim4_conf"; then
_info "Restore conf success"
eval "$_reload"
else
_err "Opps, error restore exim4 conf, please report bug to us."
fi
return 1
fi
fi
_info "Run reload: $_reload"
if eval "$_reload"; then
_info "Reload success!"
if [ "$DEPLOY_EXIM4_CONF" ]; then
_savedomainconf DEPLOY_EXIM4_CONF "$DEPLOY_EXIM4_CONF"
else
_cleardomainconf DEPLOY_EXIM4_CONF
fi
if [ "$DEPLOY_EXIM4_RELOAD" ]; then
_savedomainconf DEPLOY_EXIM4_RELOAD "$DEPLOY_EXIM4_RELOAD"
else
_cleardomainconf DEPLOY_EXIM4_RELOAD
fi
return 0
else
_err "Reload error, restoring"
if cat "$_backup_conf" >"$_exim4_conf"; then
_info "Restore conf success"
eval "$_reload"
else
_err "Opps, error restore exim4 conf, please report bug to us."
fi
return 1
fi
return 0
} }

88
deploy/vsftpd.sh

@ -4,6 +4,9 @@
#returns 0 means success, otherwise error. #returns 0 means success, otherwise error.
#DEPLOY_VSFTPD_CONF="/etc/vsftpd.conf"
#DEPLOY_VSFTPD_RELOAD="service vsftpd restart"
######## Public functions ##################### ######## Public functions #####################
#domain keyfile certfile cafile fullchain #domain keyfile certfile cafile fullchain
@ -20,7 +23,88 @@ vsftpd_deploy() {
_debug _cca "$_cca" _debug _cca "$_cca"
_debug _cfullchain "$_cfullchain" _debug _cfullchain "$_cfullchain"
_err "deploy cert to vsftpd server, Not implemented yet"
return 1
_ssl_path="/etc/acme.sh/vsftpd"
if ! mkdir -p "$_ssl_path"; then
_err "Can not create folder:$_ssl_path"
return 1
fi
_info "Copying key and cert"
_real_key="$_ssl_path/vsftpd.key"
if ! cat "$_ckey" >"$_real_key"; then
_err "Error: write key file to: $_real_key"
return 1
fi
_real_fullchain="$_ssl_path/vsftpd.chain.pem"
if ! cat "$_cfullchain" >"$_real_fullchain"; then
_err "Error: write key file to: $_real_fullchain"
return 1
fi
DEFAULT_VSFTPD_RELOAD="service vsftpd restart"
_reload="${DEPLOY_VSFTPD_RELOAD:-$DEFAULT_VSFTPD_RELOAD}"
if [ -z "$IS_RENEW" ]; then
DEFAULT_VSFTPD_CONF="/etc/vsftpd.conf"
_vsftpd_conf="${DEPLOY_VSFTPD_CONF:-$DEFAULT_VSFTPD_CONF}"
if [ ! -f "$_vsftpd_conf" ]; then
if [ -z "$DEPLOY_VSFTPD_CONF" ]; then
_err "vsftpd conf is not found, please define DEPLOY_VSFTPD_CONF"
return 1
else
_err "It seems that the specified vsftpd conf is not valid, please check."
return 1
fi
fi
if [ ! -w "$_vsftpd_conf" ]; then
_err "The file $_vsftpd_conf is not writable, please change the permission."
return 1
fi
_backup_conf="$DOMAIN_BACKUP_PATH/vsftpd.conf.bak"
_info "Backup $_vsftpd_conf to $_backup_conf"
cp "$_vsftpd_conf" "$_backup_conf"
_info "Modify vsftpd conf: $_vsftpd_conf"
if _setopt "$_vsftpd_conf" "rsa_cert_file" "=" "$_real_fullchain" \
&& _setopt "$_vsftpd_conf" "rsa_private_key_file" "=" "$_real_key" \
&& _setopt "$_vsftpd_conf" "ssl_enable" "=" "YES"; then
_info "Set config success!"
else
_err "Config vsftpd server error, please report bug to us."
_info "Restoring vsftpd conf"
if cat "$_backup_conf" >"$_vsftpd_conf"; then
_info "Restore conf success"
eval "$_reload"
else
_err "Opps, error restore vsftpd conf, please report bug to us."
fi
return 1
fi
fi
_info "Run reload: $_reload"
if eval "$_reload"; then
_info "Reload success!"
if [ "$DEPLOY_VSFTPD_CONF" ]; then
_savedomainconf DEPLOY_VSFTPD_CONF "$DEPLOY_VSFTPD_CONF"
else
_cleardomainconf DEPLOY_VSFTPD_CONF
fi
if [ "$DEPLOY_VSFTPD_RELOAD" ]; then
_savedomainconf DEPLOY_VSFTPD_RELOAD "$DEPLOY_VSFTPD_RELOAD"
else
_cleardomainconf DEPLOY_VSFTPD_RELOAD
fi
return 0
else
_err "Reload error, restoring"
if cat "$_backup_conf" >"$_vsftpd_conf"; then
_info "Restore conf success"
eval "$_reload"
else
_err "Opps, error restore vsftpd conf, please report bug to us."
fi
return 1
fi
return 0
} }

26
dnsapi/README.md

@ -323,6 +323,32 @@ acme.sh --issue --dns dns_cyon -d example.com -d www.example.com
The `CY_Username`, `CY_Password` and `CY_OTP_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. The `CY_Username`, `CY_Password` and `CY_OTP_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 17. Use Domain-Offensive/Resellerinterface/Domainrobot API
You will need your login credentials (Partner ID+Password) to the Resellerinterface, and export them before you run `acme.sh`:
```
export DO_PID="KD-1234567"
export DO_PW="cdfkjl3n2"
```
Ok, let's issue a cert now:
```
acme.sh --issue --dns dns_do -d example.com -d www.example.com
```
## 18. Use Gandi LiveDNS API
You must enable the new Gandi LiveDNS API first and the create your api key, See: http://doc.livedns.gandi.net/
```
export GANDI_LIVEDNS_KEY="fdmlfsdklmfdkmqsdfk"
```
Ok, let's issue a cert now:
```
acme.sh --issue --dns dns_gandi_livedns -d example.com -d www.example.com
```
# Use custom API # Use custom API
If your API is not supported yet, you can write your own DNS API. If your API is not supported yet, you can write your own DNS API.

148
dnsapi/dns_do.sh

@ -0,0 +1,148 @@
#!/usr/bin/env sh
# DNS API for Domain-Offensive / Resellerinterface / Domainrobot
# Report bugs at https://github.com/seidler2547/acme.sh/issues
# set these environment variables to match your customer ID and password:
# DO_PID="KD-1234567"
# DO_PW="cdfkjl3n2"
DO_URL="https://soap.resellerinterface.de/"
######## Public functions #####################
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_do_add() {
fulldomain=$1
txtvalue=$2
if _dns_do_authenticate; then
_info "Adding TXT record to ${_domain} as ${fulldomain}"
_dns_do_soap createRR origin "${_domain}" name "${fulldomain}" type TXT data "${txtvalue}" ttl 300
if _contains "${response}" '>success<'; then
return 0
fi
_err "Could not create resource record, check logs"
fi
return 1
}
#fulldomain
dns_do_rm() {
fulldomain=$1
if _dns_do_authenticate; then
if _dns_do_list_rrs; then
_dns_do_had_error=0
for _rrid in ${_rr_list}; do
_info "Deleting resource record $_rrid for $_domain"
_dns_do_soap deleteRR origin "${_domain}" rrid "${_rrid}"
if ! _contains "${response}" '>success<'; then
_dns_do_had_error=1
_err "Could not delete resource record for ${_domain}, id ${_rrid}"
fi
done
return $_dns_do_had_error
fi
fi
return 1
}
#################### Private functions below ##################################
_dns_do_authenticate() {
_info "Authenticating as ${DO_PID}"
_dns_do_soap authPartner partner "${DO_PID}" password "${DO_PW}"
if _contains "${response}" '>success<'; then
_get_root "$fulldomain"
_debug "_domain $_domain"
return 0
else
_err "Authentication failed, are DO_PID and DO_PW set correctly?"
fi
return 1
}
_dns_do_list_rrs() {
_dns_do_soap getRRList origin "${_domain}"
if ! _contains "${response}" 'SOAP-ENC:Array'; then
_err "getRRList origin ${_domain} failed"
return 1
fi
_rr_list="$(echo "${response}" \
| tr -d "\n\r\t" \
| sed -e 's/<item xsi:type="ns2:Map">/\n/g' \
| grep ">$(_regexcape "$fulldomain")</value>" \
| sed -e 's/<\/item>/\n/g' \
| grep '>id</key><value' \
| _egrep_o '>[0-9]{1,16}<' \
| tr -d '><')"
[ "${_rr_list}" ]
}
_dns_do_soap() {
func="$1"
shift
# put the parameters to xml
body="<tns:${func} xmlns:tns=\"${DO_URL}\">"
while [ "$1" ]; do
_k="$1"
shift
_v="$1"
shift
body="$body<$_k>$_v</$_k>"
done
body="$body</tns:${func}>"
_debug2 "SOAP request ${body}"
# build SOAP XML
_xml='<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>'"$body"'</env:Body>
</env:Envelope>'
# set SOAP headers
export _H1="SOAPAction: ${DO_URL}#${func}"
if ! response="$(_post "${_xml}" "${DO_URL}")"; then
_err "Error <$1>"
return 1
fi
_debug2 "SOAP response $response"
# retrieve cookie header
_H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)"
export _H2
return 0
}
_get_root() {
domain=$1
i=1
_dns_do_soap getDomainList
_all_domains="$(echo "${response}" \
| tr -d "\n\r\t " \
| _egrep_o 'domain</key><value[^>]+>[^<]+' \
| sed -e 's/^domain<\/key><value[^>]*>//g')"
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
if [ -z "$h" ]; then
return 1
fi
if _contains "${_all_domains}" "^$(_regexcape "$h")\$"; then
_domain="$h"
return 0
fi
i=$(_math $i + 1)
done
_debug "$domain not found"
return 1
}
_regexcape() {
echo "$1" | sed -e 's/\([]\.$*^[]\)/\\\1/g'
}

123
dnsapi/dns_gandi_livedns.sh

@ -0,0 +1,123 @@
#!/usr/bin/env sh
# Gandi LiveDNS v5 API
# http://doc.livedns.gandi.net/
# currently under beta
#
# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable
#
#Author: Frédéric Crozat <fcrozat@suse.com>
#Report Bugs here: https://github.com/fcrozat/acme.sh
#
######## Public functions #####################
GANDI_LIVEDNS_API="https://dns.beta.gandi.net/api/v5"
#Usage: dns_gandi_livedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_gandi_livedns_add() {
fulldomain=$1
txtvalue=$2
if [ -z "$GANDI_LIVEDNS_KEY" ]; then
_err "No API key specifed for Gandi LiveDNS."
_err "Create your key and export it as GANDI_LIVEDNS_KEY"
return 1
fi
_saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
_debug domain "$_domain"
_debug sub_domain "$_sub_domain"
_gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \
&& _contains "$response" '{"message": "Zone Record Created"}' \
&& _info "Add $(__green "success")"
}
#Usage: fulldomain txtvalue
#Remove the txt record after validation.
dns_gandi_livedns_rm() {
fulldomain=$1
txtvalue=$2
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug fulldomain "$fulldomain"
_debug domain "$_domain"
_debug sub_domain "$_sub_domain"
_gandi_livedns_rest DELETE "domains/$_domain/records/$_sub_domain/TXT" ""
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
_get_root() {
domain=$1
i=2
p=1
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug h "$h"
if [ -z "$h" ]; then
#not valid
return 1
fi
if ! _gandi_livedns_rest GET "domains/$h"; then
return 1
fi
if _contains "$response" '"code": 401'; then
_err "$response"
return 1
elif _contains "$response" '"code": 404'; then
_debug "$h not found"
else
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain="$h"
return 0
fi
p="$i"
i=$(_math "$i" + 1)
done
return 1
}
_gandi_livedns_rest() {
m=$1
ep="$2"
data="$3"
_debug "$ep"
export _H1="Content-Type: application/json"
export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY"
if [ "$m" = "GET" ]; then
response="$(_get "$GANDI_LIVEDNS_API/$ep")"
else
_debug data "$data"
response="$(_post "$data" "$GANDI_LIVEDNS_API/$ep" "" "$m")"
fi
if [ "$?" != "0" ]; then
_err "error $ep"
return 1
fi
_debug2 response "$response"
return 0
}

31
dnsapi/dns_lua.sh

@ -81,7 +81,36 @@ dns_lua_add() {
#fulldomain #fulldomain
dns_lua_rm() { dns_lua_rm() {
fulldomain=$1 fulldomain=$1
txtvalue=$2
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _domain_id "$_domain_id"
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_debug "Getting txt records"
_LUA_rest GET "zones/${_domain_id}/records"
count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ")
_debug count "$count"
if [ "$count" = "0" ]; then
_info "Don't need to remove."
else
record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1)
_debug "record_id" "$record_id"
if [ -z "$record_id" ]; then
_err "Can not get record id to remove."
return 1
fi
if ! _LUA_rest DELETE "/zones/$_domain_id/records/$record_id"; then
_err "Delete record error."
return 1
fi
_contains "$response" "$record_id"
fi
} }
#################### Private functions below ################################## #################### Private functions below ##################################
@ -129,7 +158,7 @@ _LUA_rest() {
export _H1="Accept: application/json" export _H1="Accept: application/json"
export _H2="Authorization: Basic $LUA_auth" export _H2="Authorization: Basic $LUA_auth"
if [ "$data" ]; then
if [ "$m" != "GET" ]; then
_debug data "$data" _debug data "$data"
response="$(_post "$data" "$LUA_Api/$ep" "" "$m")" response="$(_post "$data" "$LUA_Api/$ep" "" "$m")"
else else

31
dnsapi/dns_me.sh

@ -78,7 +78,36 @@ dns_me_add() {
#fulldomain #fulldomain
dns_me_rm() { dns_me_rm() {
fulldomain=$1 fulldomain=$1
txtvalue=$2
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _domain_id "$_domain_id"
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_debug "Getting txt records"
_me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT"
count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2)
_debug count "$count"
if [ "$count" = "0" ]; then
_info "Don't need to remove."
else
record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | head -n 1)
_debug "record_id" "$record_id"
if [ -z "$record_id" ]; then
_err "Can not get record id to remove."
return 1
fi
if ! _me_rest DELETE "$_domain_id/records/$record_id"; then
_err "Delete record error."
return 1
fi
_contains "$response" ''
fi
} }
#################### Private functions below ################################## #################### Private functions below ##################################
@ -130,7 +159,7 @@ _me_rest() {
export _H2="x-dnsme-requestDate: $cdate" export _H2="x-dnsme-requestDate: $cdate"
export _H3="x-dnsme-hmac: $hmac" export _H3="x-dnsme-hmac: $hmac"
if [ "$data" ]; then
if [ "$m" != "GET" ]; then
_debug data "$data" _debug data "$data"
response="$(_post "$data" "$ME_Api/$ep" "" "$m")" response="$(_post "$data" "$ME_Api/$ep" "" "$m")"
else else

Loading…
Cancel
Save