fix: harden mx helper and cleanup flow
This commit is contained in:
@@ -3,9 +3,15 @@ set -eu
|
||||
set -f
|
||||
|
||||
DA_BIN="${MAIL_LOGIN_DA_BIN:-/usr/bin/da}"
|
||||
CONFIG_FILE="${MAIL_LOGIN_HELPER_CONFIG:-/usr/local/hitme_plugins/mail-login-helper/config/helper-settings.conf}"
|
||||
AUDIT_LOG="${MAIL_LOGIN_AUDIT_LOG:-/usr/local/hitme_plugins/mail-login-helper/logs/audit.log}"
|
||||
STATE_DIR="${MAIL_LOGIN_STATE_DIR:-/usr/local/hitme_plugins/mail-login-helper/state}"
|
||||
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
# shellcheck disable=SC1090
|
||||
. "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
audit() {
|
||||
dir=$(dirname "$AUDIT_LOG")
|
||||
mkdir -p "$dir"
|
||||
@@ -25,6 +31,27 @@ clean_label() {
|
||||
printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g; s/^-*//; s/-*$//'
|
||||
}
|
||||
|
||||
first_label() {
|
||||
printf '%s' "$1" | sed 's/:.*$//' | awk -F. '{print $1}'
|
||||
}
|
||||
|
||||
host_allowed() {
|
||||
allowed="${MAIL_LOGIN_ALLOWED_SOURCE_HOSTS:-}"
|
||||
[ -n "$allowed" ] || return 1
|
||||
old_ifs=$IFS
|
||||
IFS=,
|
||||
for host in $allowed; do
|
||||
normalized=$(printf '%s' "$host" | tr '[:upper:]' '[:lower:]' | sed 's#^https\?://##; s#/.*$##; s/:[0-9][0-9]*$//; s/^ *//; s/ *$//')
|
||||
[ "$normalized" = "$SOURCE_HOST" ] && IFS=$old_ifs && return 0
|
||||
done
|
||||
IFS=$old_ifs
|
||||
return 1
|
||||
}
|
||||
|
||||
valid_ip() {
|
||||
php -r 'exit(filter_var($argv[1], FILTER_VALIDATE_IP) ? 0 : 1);' "$1"
|
||||
}
|
||||
|
||||
if [ "$#" -eq 0 ] && [ -n "${SSH_ORIGINAL_COMMAND:-}" ]; then
|
||||
# The authorized_keys forced command receives the requested command here.
|
||||
# All accepted fields are validated below before use.
|
||||
@@ -43,11 +70,15 @@ REDIRECT_PATH="${8:-}"
|
||||
[ "$COMMAND" = "mail-login-create-url" ] || fail
|
||||
printf '%s' "$USERNAME_ARG" | grep -Eq '^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$' || fail
|
||||
printf '%s' "$SOURCE_HOST" | grep -Eq '^[A-Za-z0-9.-]+$' || fail
|
||||
printf '%s' "$SERVER_NAME" | grep -Eq '^[A-Za-z0-9-]{1,32}$' || fail
|
||||
SOURCE_HOST=$(printf '%s' "$SOURCE_HOST" | tr '[:upper:]' '[:lower:]')
|
||||
host_allowed || fail
|
||||
SERVER_NAME=$(first_label "$SOURCE_HOST")
|
||||
SERVER_NAME=$(clean_label "$SERVER_NAME")
|
||||
printf '%s' "$SERVER_NAME" | grep -Eq '^[a-z0-9-]{1,32}$' || fail
|
||||
printf '%s' "$TTL" | grep -Eq '^[0-9]+$' || fail
|
||||
[ "$TTL" -ge 5 ] && [ "$TTL" -le 300 ] || fail
|
||||
[ "$USER_IP_BOUND" = "0" ] || [ "$USER_IP_BOUND" = "1" ] || fail
|
||||
printf '%s' "$CLIENT_IP" | grep -Eq '^[0-9A-Fa-f:.]+$' || fail
|
||||
valid_ip "$CLIENT_IP" || fail
|
||||
case "$REDIRECT_PATH" in
|
||||
/*) ;;
|
||||
*) fail ;;
|
||||
@@ -86,8 +117,8 @@ case "$URL" in
|
||||
*) fail ;;
|
||||
esac
|
||||
|
||||
printf '{"timestamp":%s,"correlation":"%s","username":"%s","source_host":"%s","client_ip":"%s","ttl":%s,"ip_bound":%s}\n' \
|
||||
"$TIMESTAMP" "$CORRELATION" "$USERNAME_ARG" "$SOURCE_HOST" "$CLIENT_IP" "$TTL" "$USER_IP_BOUND" > "$STATE_DIR/$CORRELATION.json"
|
||||
printf '{"timestamp":%s,"expires":%s,"correlation":"%s","username":"%s","source_host":"%s","client_ip":"%s","ttl":%s,"ip_bound":%s,"redirect_path":"%s","status":"created"}\n' \
|
||||
"$TIMESTAMP" "$((TIMESTAMP + TTL))" "$CORRELATION" "$USERNAME_ARG" "$SOURCE_HOST" "$CLIENT_IP" "$TTL" "$USER_IP_BOUND" "$REDIRECT_PATH" > "$STATE_DIR/$CORRELATION.json"
|
||||
chmod 600 "$STATE_DIR/$CORRELATION.json"
|
||||
audit "create_login_url" "success" "$CORRELATION" "$USERNAME_ARG" "$SOURCE_HOST" "$CLIENT_IP"
|
||||
printf 'URL: %s\n' "$URL"
|
||||
|
||||
Reference in New Issue
Block a user