Compare commits
18 commits
Author | SHA1 | Date | |
---|---|---|---|
Jérémy Dubois | fdf9357792 | ||
Jérémy Dubois | d04d68f6cb | ||
Jérémy Dubois | 514cd2e50f | ||
Jérémy Dubois | 30ef252ff5 | ||
Jérémy Dubois | e0c29cfcf1 | ||
Jérémy Dubois | 2afa4ab449 | ||
Jérémy Dubois | a750b71e05 | ||
Jérémy Dubois | 24249d829c | ||
Jérémy Dubois | 7382947fc3 | ||
Jérémy Dubois | bd5e02bb87 | ||
Jérémy Dubois | e33722d440 | ||
Jérémy Dubois | 467ea5fe3d | ||
Jérémy Dubois | 3b3e0b01bf | ||
Jérémy Dubois | 34b53e63f2 | ||
Jérémy Dubois | e886ca9549 | ||
Jérémy Dubois | 5f792272c6 | ||
f58712f2b3 | |||
38aac7b137 |
34
CHANGELOG.md
34
CHANGELOG.md
|
@ -12,10 +12,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
* Fix mode of shellpki script in README file when installing it
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
|
## [22.12.2] 2022-12-13
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
* Defaults default_crl_days to 2 years instead of 1
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Fix ${CRL} and ${CA_DIR} rights so that CRL file can be read by openvpn
|
||||||
|
|
||||||
|
## [22.12.1] 2022-12-02
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* cert-expirations.sh: check CARP state only when checking ca and certs expirations
|
||||||
|
* Fix path variables in cert-expirations.sh
|
||||||
|
|
||||||
|
## [22.12] 2022-12-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* The key file can be read and written only by the owner
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
* Use genpkey and pkey instead of genrsa and rsa
|
||||||
|
* Improved cert-expirations.sh for better readability of its ouput
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Create index.txt.attr file
|
||||||
|
|
||||||
## [22.04] 2022-04-14
|
## [22.04] 2022-04-14
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
22
README.md
22
README.md
|
@ -16,7 +16,7 @@ be copied to [ansible-roles/openvpn](https://gitea.evolix.org/evolix/ansible-rol
|
||||||
useradd shellpki --system -M --home-dir /etc/shellpki --shell /usr/sbin/nologin
|
useradd shellpki --system -M --home-dir /etc/shellpki --shell /usr/sbin/nologin
|
||||||
mkdir /etc/shellpki
|
mkdir /etc/shellpki
|
||||||
install -m 0640 openssl.cnf /etc/shellpki/
|
install -m 0640 openssl.cnf /etc/shellpki/
|
||||||
install -m 0755 shellpki /usr/local/sbin/shellpki
|
install -m 0750 shellpki /usr/local/sbin/shellpki
|
||||||
chown -R shellpki: /etc/shellpki
|
chown -R shellpki: /etc/shellpki
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ chown -R shellpki: /etc/shellpki
|
||||||
useradd -r 1..1000 -d /etc/shellpki -s /sbin/nologin _shellpki
|
useradd -r 1..1000 -d /etc/shellpki -s /sbin/nologin _shellpki
|
||||||
mkdir /etc/shellpki
|
mkdir /etc/shellpki
|
||||||
install -m 0640 openssl.cnf /etc/shellpki/
|
install -m 0640 openssl.cnf /etc/shellpki/
|
||||||
install -m 0755 shellpki /usr/local/sbin/shellpki
|
install -m 0750 shellpki /usr/local/sbin/shellpki
|
||||||
chown -R _shellpki:_shellpki /etc/shellpki
|
chown -R _shellpki:_shellpki /etc/shellpki
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
@ -137,6 +137,24 @@ Show help :
|
||||||
shellpki help
|
shellpki help
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
## Loop
|
||||||
|
|
||||||
|
We can loop over a file to revoke or create many certificates at once.
|
||||||
|
|
||||||
|
To revoke :
|
||||||
|
|
||||||
|
~~~
|
||||||
|
$ read CA_PASS
|
||||||
|
$ for cert_name in $(cat /path/to/file_certs_to_revoke); do CA_PASSWORD=$CA_PASS shellpki revoke $cert_name --non-interactive ; done
|
||||||
|
~~~
|
||||||
|
|
||||||
|
To create (without `--replace-existing`) or renew (with `--replace-existing`), with a password on the client key :
|
||||||
|
|
||||||
|
~~~
|
||||||
|
$ read CA_PASS
|
||||||
|
$ for cert_name in $(cat /path/to/file_certs_to_create); do apg -n 1 -m 16 -M lcN > /path/to/folder/to/store/${cert_name}.passwd; CA_PASSWORD=$CA_PASS shellpki create --replace-existing --non-interactive --password-file /path/to/folder/to/store/${cert_name}.passwd ${cert_name}; done
|
||||||
|
~~~
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
ShellPKI is an [Evolix](https://evolix.com) project and is licensed
|
ShellPKI is an [Evolix](https://evolix.com) project and is licensed
|
||||||
|
|
|
@ -1,28 +1,126 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
VERSION="22.04"
|
VERSION="22.12.1"
|
||||||
|
|
||||||
carp=$(/sbin/ifconfig carp0 2>/dev/null | grep 'status' | cut -d' ' -f2)
|
show_version() {
|
||||||
|
cat <<END
|
||||||
|
cert-expirations.sh version ${VERSION}
|
||||||
|
|
||||||
if [ "$carp" = "backup" ]; then
|
Copyright 2020-2022 Evolix <info@evolix.fr>,
|
||||||
exit 0
|
Jérémy Lecour <jlecour@evolix.fr>,
|
||||||
fi
|
Jérémy Dubois <jdubois@evolix.fr>
|
||||||
|
and others.
|
||||||
|
|
||||||
echo "Warning : all times are in UTC !\n"
|
cert-expirations.sh comes with ABSOLUTELY NO WARRANTY. This is free software,
|
||||||
|
and you are welcome to redistribute it under certain conditions.
|
||||||
|
See the MIT Licence for details.
|
||||||
|
END
|
||||||
|
}
|
||||||
|
|
||||||
echo "CA certificate:"
|
show_usage() {
|
||||||
openssl x509 -enddate -noout -in /etc/shellpki/cacert.pem \
|
cat <<END
|
||||||
| cut -d '=' -f 2 \
|
Usage: ${0} [--version]
|
||||||
| sed -e "s/^\(.*\)\ \(20..\).*/- \2 \1/"
|
END
|
||||||
|
}
|
||||||
|
|
||||||
echo ""
|
check_carp_state() {
|
||||||
|
if [ "${SYSTEM}" = "openbsd" ]; then
|
||||||
|
carp=$(/sbin/ifconfig carp0 2>/dev/null | grep 'status' | cut -d' ' -f2)
|
||||||
|
|
||||||
echo "Client certificates:"
|
if [ "$carp" = "backup" ]; then
|
||||||
cat /etc/shellpki/index.txt \
|
exit 0
|
||||||
| grep ^V \
|
fi
|
||||||
| awk -F "/" '{print $1,$5}' \
|
fi
|
||||||
| awk '{print $2,$5}' \
|
}
|
||||||
| sed 's/CN=//' \
|
|
||||||
| sed -E 's/([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})Z (.*)/- 20\1 \2 \3 \4:\5:\6 \7/' \
|
check_ca_expiration() {
|
||||||
| awk '{if ($3 == "01") $3="Jan"; else if ($3 == "02") $3="Feb"; else if ($3 == "03") $3="Mar"; else if ($3 == "04") $3="Apr"; else if ($3 == "05") $3="May"; else if ($3 == "06") $3="Jun"; else if ($3 == "07") $3="Jul"; else if ($3 == "08") $3="Aug"; else if ($3 == "09") $3="Sep"; else if ($3 == "10") $3="Oct"; else if ($3 == "11") $3="Nov"; else if ($3 == "12") $3="Dec"; print $0;}' \
|
echo "CA certificate:"
|
||||||
| sort -n -k 2 -k 3M -k 4
|
openssl x509 -enddate -noout -in ${cacert_path} \
|
||||||
|
| cut -d '=' -f 2 \
|
||||||
|
| sed -e "s/^\(.*\)\ \(20..\).*/- \2 \1/"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_certs_expiration() {
|
||||||
|
# Syntax "cmd | { while read line; do var="foo"; done echo $var }" needed, otherwise $var is empty at the end of while loop
|
||||||
|
grep ^V ${index_path} \
|
||||||
|
| awk -F "/" '{print $1,$5}' \
|
||||||
|
| awk '{print $2,$5}' \
|
||||||
|
| sed 's/CN=//' \
|
||||||
|
| sed -E 's/([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})([[:digit:]]{2})Z (.*)/- 20\1 \2 \3 \4:\5:\6 \7/' \
|
||||||
|
| awk '{if ($3 == "01") $3="Jan"; else if ($3 == "02") $3="Feb"; else if ($3 == "03") $3="Mar"; else if ($3 == "04") $3="Apr"; else if ($3 == "05") $3="May"; else if ($3 == "06") $3="Jun"; else if ($3 == "07") $3="Jul"; else if ($3 == "08") $3="Aug"; else if ($3 == "09") $3="Sep"; else if ($3 == "10") $3="Oct"; else if ($3 == "11") $3="Nov"; else if ($3 == "12") $3="Dec"; print $0;}' \
|
||||||
|
| sort -n -k 2 -k 3M -k 4 | {
|
||||||
|
while read -r line; do
|
||||||
|
|
||||||
|
# Predicting expirations - OpenBSD case (date is not the same than in Linux)
|
||||||
|
if [ "${SYSTEM}" = "openbsd" ]; then
|
||||||
|
# Already expired if expiration date is before now
|
||||||
|
if [ "$(TZ=:Zulu date -jf "%Y %b %d %H:%M:%S" "$(echo "$line" | awk '{print $2,$3,$4,$5}')" +%s)" -le "$(date +%s)" ]; then
|
||||||
|
expired_certs="${expired_certs}$line\n"
|
||||||
|
# Expiring soon if expiration date is after now and before now + $somedays days
|
||||||
|
elif [ "$(TZ=:Zulu date -jf "%Y %b %d %H:%M:%S" "$(echo "$line" | awk '{print $2,$3,$4,$5}')" +%s)" -gt "$(date +%s)" ] && [ "$(TZ=:Zulu date -jf "%Y %b %d %H:%M:%S" "$(echo "$line" | awk '{print $2,$3,$4,$5}')" +%s)" -lt "$(($(date +%s) + somedays))" ]; then
|
||||||
|
expiring_soon_certs="${expiring_soon_certs}$line\n"
|
||||||
|
# Still valid for a time if expiration date is after now + $somedays days
|
||||||
|
elif [ "$(TZ=:Zulu date -jf "%Y %b %d %H:%M:%S" "$(echo "$line" | awk '{print $2,$3,$4,$5}')" +%s)" -ge "$(($(date +%s) + somedays))" ]; then
|
||||||
|
still_valid_certs="${still_valid_certs}$line\n"
|
||||||
|
fi
|
||||||
|
# Non OpenBSD cases
|
||||||
|
else
|
||||||
|
# Already expired if expiration date is before now
|
||||||
|
if [ "$(TZ=:Zulu date -d "$(echo "$line" | awk '{print $3,$4,$2,$5}')" +%s)" -le "$(date +%s)" ]; then
|
||||||
|
expired_certs="${expired_certs}$line\n"
|
||||||
|
# Expiring soon if expiration date is after now and before now + $somedays days
|
||||||
|
elif [ "$(TZ=:Zulu date -d "$(echo "$line" | awk '{print $3,$4,$2,$5}')" +%s)" -gt "$(date +%s)" ] && [ "$(TZ=:Zulu date -d "$(echo "$line" | awk '{print $3,$4,$2,$5}')" +%s)" -lt "$(($(date +%s) + somedays))" ]; then
|
||||||
|
expiring_soon_certs="${expiring_soon_certs}$line\n"
|
||||||
|
# Still valid for a time if expiration date is after now + $somedays days
|
||||||
|
elif [ "$(TZ=:Zulu date -d "$(echo "$line" | awk '{print $3,$4,$2,$5}')" +%s)" -ge "$(($(date +%s) + somedays))" ]; then
|
||||||
|
still_valid_certs="${still_valid_certs}$line\n"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Expired client certificates:"
|
||||||
|
echo "${expired_certs}"
|
||||||
|
echo "Valid client certificates expiring soon (in less than $((somedays / 60 / 60 / 24)) days):"
|
||||||
|
echo "${expiring_soon_certs}"
|
||||||
|
echo "Valid client certificates expiring later (in more than $((somedays / 60 / 60 / 24)) days):"
|
||||||
|
echo "${still_valid_certs}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
SYSTEM=$(uname | tr '[:upper:]' '[:lower:]')
|
||||||
|
cacert_path="/etc/shellpki/cacert.pem"
|
||||||
|
index_path="/etc/shellpki/index.txt"
|
||||||
|
somedays="3456000" # 40 days currently
|
||||||
|
expired_certs=""
|
||||||
|
expiring_soon_certs=""
|
||||||
|
still_valid_certs=""
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
version|--version)
|
||||||
|
show_version
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
|
||||||
|
help|--help)
|
||||||
|
show_usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
|
||||||
|
"")
|
||||||
|
check_carp_state
|
||||||
|
echo "Warning : all times are in UTC !"
|
||||||
|
echo ""
|
||||||
|
check_ca_expiration
|
||||||
|
echo ""
|
||||||
|
check_certs_expiration
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
show_usage >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# VERSION="22.04"
|
# VERSION="22.12.2"
|
||||||
|
|
||||||
[ ca ]
|
[ ca ]
|
||||||
default_ca = CA_default
|
default_ca = CA_default
|
||||||
|
@ -14,7 +14,7 @@ crl = $dir/crl.pem
|
||||||
private_key = $dir/cakey.key
|
private_key = $dir/cakey.key
|
||||||
RANDFILE = $dir/.rand
|
RANDFILE = $dir/.rand
|
||||||
default_days = 365
|
default_days = 365
|
||||||
default_crl_days= 365
|
default_crl_days= 730
|
||||||
default_md = sha256
|
default_md = sha256
|
||||||
preserve = no
|
preserve = no
|
||||||
policy = policy_match
|
policy = policy_match
|
||||||
|
|
37
shellpki
37
shellpki
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
VERSION="22.04"
|
VERSION="22.12.2"
|
||||||
|
|
||||||
show_version() {
|
show_version() {
|
||||||
cat <<END
|
cat <<END
|
||||||
|
@ -137,14 +137,14 @@ warning() {
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_ca_password() {
|
verify_ca_password() {
|
||||||
"${OPENSSL_BIN}" rsa \
|
"${OPENSSL_BIN}" pkey \
|
||||||
-in "${CA_KEY}" \
|
-in "${CA_KEY}" \
|
||||||
-passin pass:"${CA_PASSWORD}" \
|
-passin pass:"${CA_PASSWORD}" \
|
||||||
>/dev/null 2>&1
|
>/dev/null 2>&1
|
||||||
}
|
}
|
||||||
get_real_path() {
|
get_real_path() {
|
||||||
# --canonicalize is supported on Linux
|
# --canonicalize is supported on Linux
|
||||||
# -f is supported on Linux and OpenBSD
|
# -f is supported on Linux and OpenBSD
|
||||||
readlink -f -- "${1}"
|
readlink -f -- "${1}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,9 +224,10 @@ replace_existing_or_abort() {
|
||||||
init() {
|
init() {
|
||||||
umask 0177
|
umask 0177
|
||||||
|
|
||||||
[ -d "${CA_DIR}" ] || mkdir -m 0750 "${CA_DIR}"
|
[ -d "${CA_DIR}" ] || mkdir -m 0751 "${CA_DIR}"
|
||||||
[ -d "${CRT_DIR}" ] || mkdir -m 0750 "${CRT_DIR}"
|
[ -d "${CRT_DIR}" ] || mkdir -m 0750 "${CRT_DIR}"
|
||||||
[ -f "${INDEX_FILE}" ] || touch "${INDEX_FILE}"
|
[ -f "${INDEX_FILE}" ] || touch "${INDEX_FILE}"
|
||||||
|
[ -f "${INDEX_FILE}.attr" ] || touch "${INDEX_FILE}.attr"
|
||||||
[ -f "${CRL}" ] || touch "${CRL}"
|
[ -f "${CRL}" ] || touch "${CRL}"
|
||||||
[ -f "${SERIAL}" ] || echo "01" > "${SERIAL}"
|
[ -f "${SERIAL}" ] || echo "01" > "${SERIAL}"
|
||||||
|
|
||||||
|
@ -278,17 +279,18 @@ init() {
|
||||||
|
|
||||||
passout_arg=""
|
passout_arg=""
|
||||||
if [ -n "${CA_PASSWORD:-}" ]; then
|
if [ -n "${CA_PASSWORD:-}" ]; then
|
||||||
passout_arg="-passout pass:${CA_PASSWORD}"
|
passout_arg="-pass pass:${CA_PASSWORD}"
|
||||||
elif [ "${non_interactive}" -eq 1 ]; then
|
elif [ "${non_interactive}" -eq 1 ]; then
|
||||||
error "In non-interactive mode, you must pass CA_PASSWORD as environment variable."
|
error "In non-interactive mode, you must pass CA_PASSWORD as environment variable."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f "${CA_KEY}" ]; then
|
if [ ! -f "${CA_KEY}" ]; then
|
||||||
"${OPENSSL_BIN}" genrsa \
|
"${OPENSSL_BIN}" genpkey \
|
||||||
|
-algorithm RSA \
|
||||||
-out "${CA_KEY}" \
|
-out "${CA_KEY}" \
|
||||||
${passout_arg} \
|
${passout_arg} \
|
||||||
-aes256 \
|
-aes256 \
|
||||||
"${CA_KEY_LENGTH}" \
|
-pkeyopt "rsa_keygen_bits:${CA_KEY_LENGTH}" \
|
||||||
>/dev/null 2>&1
|
>/dev/null 2>&1
|
||||||
# shellcheck disable=SC2181
|
# shellcheck disable=SC2181
|
||||||
if [ "$?" -ne 0 ]; then
|
if [ "$?" -ne 0 ]; then
|
||||||
|
@ -355,9 +357,10 @@ ocsp() {
|
||||||
port=$(echo "${ocsp_uri}" | cut -d':' -f2)
|
port=$(echo "${ocsp_uri}" | cut -d':' -f2)
|
||||||
|
|
||||||
if [ ! -f "${OCSP_KEY}" ]; then
|
if [ ! -f "${OCSP_KEY}" ]; then
|
||||||
"${OPENSSL_BIN}" genrsa \
|
"${OPENSSL_BIN}" genpkey \
|
||||||
|
-algorithm RSA \
|
||||||
-out "${OCSP_KEY}" \
|
-out "${OCSP_KEY}" \
|
||||||
"${KEY_LENGTH}" \
|
-pkeyopt "rsa_keygen_bits:${KEY_LENGTH}" \
|
||||||
>/dev/null 2>&1
|
>/dev/null 2>&1
|
||||||
# shellcheck disable=SC2181
|
# shellcheck disable=SC2181
|
||||||
if [ "$?" -ne 0 ]; then
|
if [ "$?" -ne 0 ]; then
|
||||||
|
@ -680,17 +683,19 @@ create() {
|
||||||
# generate private key
|
# generate private key
|
||||||
pass_args=""
|
pass_args=""
|
||||||
if [ -n "${password_file:-}" ]; then
|
if [ -n "${password_file:-}" ]; then
|
||||||
pass_args="-aes256 -passout file:${password_file}"
|
pass_args="-aes256 -pass file:${password_file}"
|
||||||
elif [ -n "${PASSWORD:-}" ]; then
|
elif [ -n "${PASSWORD:-}" ]; then
|
||||||
pass_args="-aes256 -passout pass:${PASSWORD}"
|
pass_args="-aes256 -pass pass:${PASSWORD}"
|
||||||
fi
|
fi
|
||||||
"${OPENSSL_BIN}" genrsa \
|
"${OPENSSL_BIN}" genpkey \
|
||||||
|
-algorithm RSA \
|
||||||
-out "${key_file}" \
|
-out "${key_file}" \
|
||||||
${pass_args} \
|
${pass_args} \
|
||||||
"${KEY_LENGTH}" \
|
-pkeyopt "rsa_keygen_bits:${KEY_LENGTH}" \
|
||||||
>/dev/null 2>&1
|
>/dev/null 2>&1
|
||||||
# shellcheck disable=SC2181
|
# shellcheck disable=SC2181
|
||||||
if [ "$?" -eq 0 ]; then
|
if [ "$?" -eq 0 ]; then
|
||||||
|
chmod 600 "${key_file}"
|
||||||
echo "The KEY file is available at \`${key_file}'"
|
echo "The KEY file is available at \`${key_file}'"
|
||||||
else
|
else
|
||||||
error "Error generating the private key"
|
error "Error generating the private key"
|
||||||
|
@ -1098,9 +1103,11 @@ main() {
|
||||||
|
|
||||||
# fix right
|
# fix right
|
||||||
chown -R "${PKI_USER}":"${PKI_USER}" "${CA_DIR}"
|
chown -R "${PKI_USER}":"${PKI_USER}" "${CA_DIR}"
|
||||||
chmod 750 "${CA_DIR}" "${CRT_DIR}" "${KEY_DIR}" "${CSR_DIR}" "${PKCS12_DIR}" "${OVPN_DIR}" "${TMP_DIR}"
|
chmod 750 "${CRT_DIR}" "${KEY_DIR}" "${CSR_DIR}" "${PKCS12_DIR}" "${OVPN_DIR}" "${TMP_DIR}"
|
||||||
chmod 600 "${INDEX_FILE}"* "${SERIAL}"* "${CA_KEY}" "${CRL}"
|
chmod 600 "${INDEX_FILE}"* "${SERIAL}"* "${CA_KEY}"
|
||||||
chmod 640 "${CA_CERT}"
|
chmod 640 "${CA_CERT}"
|
||||||
|
chmod 604 "${CRL}"
|
||||||
|
chmod 751 "${CA_DIR}"
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
main "$@"
|
||||||
|
|
Loading…
Reference in a new issue