|
|
@@ -494,6 +494,8 @@ create_user() {
|
|
|
if [[ "$gen_conf" == "y" || "$gen_conf" == "Y" ]]; then
|
|
|
generate_client_config "$username" "$password"
|
|
|
fi
|
|
|
+ # Refresh banners for the new user
|
|
|
+ update_all_user_banners
|
|
|
}
|
|
|
|
|
|
delete_user() {
|
|
|
@@ -542,6 +544,9 @@ delete_user() {
|
|
|
|
|
|
sed -i "/^$username:/d" "$DB_FILE"
|
|
|
echo -e "${C_GREEN}✅ User '$username' has been completely removed.${C_RESET}"
|
|
|
+
|
|
|
+ # Clean up banner config
|
|
|
+ update_all_user_banners
|
|
|
}
|
|
|
|
|
|
edit_user() {
|
|
|
@@ -590,6 +595,7 @@ edit_user() {
|
|
|
esac
|
|
|
echo -e "\nPress ${C_YELLOW}[Enter]${C_RESET} to continue editing..." && read -r
|
|
|
done
|
|
|
+ update_all_user_banners
|
|
|
}
|
|
|
|
|
|
lock_user() {
|
|
|
@@ -706,6 +712,7 @@ renew_user() {
|
|
|
local line; line=$(grep "^$u:" "$DB_FILE"); local pass; pass=$(echo "$line"|cut -d: -f2); local limit; limit=$(echo "$line"|cut -d: -f4)
|
|
|
sed -i "s/^$u:.*/$u:$pass:$new_expire_date:$limit/" "$DB_FILE"
|
|
|
echo -e "\n${C_GREEN}✅ User '$u' has been renewed. New expiration date is ${C_YELLOW}${new_expire_date}${C_RESET}."
|
|
|
+ update_all_user_banners
|
|
|
}
|
|
|
|
|
|
cleanup_expired() {
|
|
|
@@ -2469,111 +2476,163 @@ uninstall_script() {
|
|
|
exit 0
|
|
|
}
|
|
|
|
|
|
-install_login_notifier() {
|
|
|
- # 1. Create the Wrapper Script (The core logic)
|
|
|
- local wrapper_script="/usr/local/bin/firewallfalcon-wrapper"
|
|
|
-
|
|
|
- cat > "$wrapper_script" <<'EOF'
|
|
|
-#!/bin/bash
|
|
|
-# FirewallFalcon SSH Wrapper
|
|
|
-# Forces the banner to be displayed before the shell/command
|
|
|
+# --- NATIVE DYNAMIC BANNER SYSTEM ---
|
|
|
|
|
|
-DB_FILE="/etc/firewallfalcon/users.db"
|
|
|
-USER_NAME=$(whoami)
|
|
|
-
|
|
|
-# --- BANNER GENERATION START ---
|
|
|
-# Only show for managed users
|
|
|
-if [ -f "$DB_FILE" ] && grep -q "^$USER_NAME:" "$DB_FILE"; then
|
|
|
- USER_DATA=$(grep "^$USER_NAME:" "$DB_FILE")
|
|
|
- EXPIRY_DATE=$(echo "$USER_DATA" | cut -d: -f3)
|
|
|
+update_all_user_banners() {
|
|
|
+ local banners_dir="/etc/firewallfalcon/banners"
|
|
|
+ local ssh_include_file="/etc/ssh/sshd_config.d/99-firewallfalcon-banners.conf"
|
|
|
|
|
|
- CURRENT_TS=$(date +%s)
|
|
|
- EXPIRY_TS=$(date -d "$EXPIRY_DATE" +%s 2>/dev/null)
|
|
|
+ mkdir -p "$banners_dir"
|
|
|
+ mkdir -p "$(dirname "$ssh_include_file")"
|
|
|
|
|
|
- DAYS_LEFT="Unknown"
|
|
|
- STATUS_COLOR="\033[1;32m" # Green
|
|
|
- STATUS_TEXT="ACTIVE"
|
|
|
+ # 1. Clear old config content
|
|
|
+ echo "# Dynamic User Banners Generated by FirewallFalcon" > "$ssh_include_file"
|
|
|
|
|
|
- if [ -n "$EXPIRY_TS" ]; then
|
|
|
- DIFF_SEC=$((EXPIRY_TS - CURRENT_TS))
|
|
|
- DAYS_LEFT=$((DIFF_SEC / 86400))
|
|
|
-
|
|
|
- if [ $DAYS_LEFT -lt 0 ]; then
|
|
|
- STATUS_COLOR="\033[1;31m" # Red
|
|
|
- STATUS_TEXT="EXPIRED"
|
|
|
- DAYS_LEFT="0"
|
|
|
- elif [ $DAYS_LEFT -le 3 ]; then
|
|
|
- STATUS_COLOR="\033[1;33m" # Yellow
|
|
|
- fi
|
|
|
+ # 2. Iterate users and create banners + config
|
|
|
+ if [[ -s "$DB_FILE" ]]; then
|
|
|
+ while IFS=: read -r user pass expiry limit; do
|
|
|
+ # Calculate Days Left
|
|
|
+ local current_ts=$(date +%s)
|
|
|
+ local expiry_ts=$(date -d "$expiry" +%s 2>/dev/null)
|
|
|
+ local days_left="0"
|
|
|
+ local status_text="EXPIRED"
|
|
|
+
|
|
|
+ if [ -n "$expiry_ts" ]; then
|
|
|
+ local diff_sec=$((expiry_ts - current_ts))
|
|
|
+ days_left=$((diff_sec / 86400))
|
|
|
+ if [ $days_left -ge 0 ]; then status_text="ACTIVE"; fi
|
|
|
+ fi
|
|
|
+
|
|
|
+ # Generate the plain text banner file (No color codes allowed in SSH Banner usually, or limited support)
|
|
|
+ # Standard SSH Banners are text-only. Some clients support color codes sent here, but it's risky.
|
|
|
+ # We will use clean ASCII formatting.
|
|
|
+ local user_banner_file="$banners_dir/$user"
|
|
|
+
|
|
|
+ cat > "$user_banner_file" <<EOF
|
|
|
+==================================================
|
|
|
+ 👋 Welcome, $user
|
|
|
+ --------------------------------------------------
|
|
|
+ 📊 Status : $status_text
|
|
|
+ ⏳ Days Left : $days_left Days
|
|
|
+ 📅 Expires : $expiry
|
|
|
+==================================================
|
|
|
+
|
|
|
+EOF
|
|
|
+
|
|
|
+ # Append Match Block to Config
|
|
|
+ echo "" >> "$ssh_include_file"
|
|
|
+ echo "Match User $user" >> "$ssh_include_file"
|
|
|
+ echo " Banner $user_banner_file" >> "$ssh_include_file"
|
|
|
+
|
|
|
+ done < "$DB_FILE"
|
|
|
fi
|
|
|
|
|
|
- # Print Banner to Stderr to ensure it reaches the client even if stdout is piped
|
|
|
- # (Though for interactive shells, stdout is fine. Using stdout for visibility.)
|
|
|
- echo -e "\033[1;34m==================================================\033[0m"
|
|
|
- echo -e " \033[1;36m👋 Welcome, \033[1;37m$USER_NAME\033[0m"
|
|
|
- echo -e " \033[1;34m--------------------------------------------------\033[0m"
|
|
|
- echo -e " 📊 Status : ${STATUS_COLOR}${STATUS_TEXT}\033[0m"
|
|
|
- echo -e " ⏳ Days Left : ${STATUS_COLOR}${DAYS_LEFT} Days\033[0m"
|
|
|
- echo -e " 📅 Expires : \033[1;37m${EXPIRY_DATE}\033[0m"
|
|
|
- echo -e "\033[1;34m==================================================\033[0m"
|
|
|
- echo ""
|
|
|
-fi
|
|
|
-# --- BANNER GENERATION END ---
|
|
|
-
|
|
|
-# Execute the original command
|
|
|
-if [[ -n "$SSH_ORIGINAL_COMMAND" ]]; then
|
|
|
- exec $SSH_ORIGINAL_COMMAND
|
|
|
-else
|
|
|
- # If no command, start login shell
|
|
|
- if [ -z "$SHELL" ]; then
|
|
|
- exec /bin/bash -l
|
|
|
+ # Reload SSHD to pick up changes (Reload is safer/faster than restart)
|
|
|
+ if systemctl is-active --quiet ssh; then systemctl reload ssh;
|
|
|
+ elif systemctl is-active --quiet sshd; then systemctl reload sshd; fi
|
|
|
+}
|
|
|
+
|
|
|
+install_login_notifier() {
|
|
|
+ echo -e "${C_BLUE}🔨 Setting up Native Dynamic Banners...${C_RESET}"
|
|
|
+
|
|
|
+ # 1. Ensure Directories
|
|
|
+ mkdir -p "/etc/firewallfalcon/banners"
|
|
|
+ mkdir -p "/etc/ssh/sshd_config.d"
|
|
|
+
|
|
|
+ # 2. Configure Main sshd_config to Include our file
|
|
|
+ local main_config="/etc/ssh/sshd_config"
|
|
|
+ local include_line="Include /etc/ssh/sshd_config.d/*.conf"
|
|
|
+
|
|
|
+ if grep -q "^Include /etc/ssh/sshd_config.d/\*\.conf" "$main_config"; then
|
|
|
+ : # Already valid
|
|
|
+ elif grep -q "^Include " "$main_config"; then
|
|
|
+ # Some include exists, check if it covers us, otherwise append ours
|
|
|
+ if ! grep -q "sshd_config.d" "$main_config"; then
|
|
|
+ # Prepend to ensure it's loaded early (though Match blocks usually work anywhere)
|
|
|
+ sed -i "1i $include_line" "$main_config"
|
|
|
+ fi
|
|
|
else
|
|
|
- exec "$SHELL" -l
|
|
|
+ # No Indludes at all, add it to the top
|
|
|
+ sed -i "1i $include_line" "$main_config"
|
|
|
fi
|
|
|
-fi
|
|
|
-EOF
|
|
|
- chmod +x "$wrapper_script"
|
|
|
|
|
|
- # Clean up old profile script if exists (switching methods)
|
|
|
+ # 3. Clean up OLD methods (Wrapper / Profile) to prevent double banners
|
|
|
+ rm -f "/usr/local/bin/firewallfalcon-wrapper"
|
|
|
rm -f "/etc/profile.d/z_firewallfalcon_banner.sh"
|
|
|
+ sed -i '/ForceCommand \/usr\/local\/bin\/firewallfalcon-wrapper/d' "$main_config"
|
|
|
+ sed -i '/Match User !root/d' "$main_config"
|
|
|
+
|
|
|
+ # 4. Global Config cleanup
|
|
|
+ # Ensure standard Banner is disabled so we don't get duplicates
|
|
|
+ sed -i 's/^Banner /#Banner /' "$main_config"
|
|
|
+ if grep -q "^PrintMotd" "$main_config"; then
|
|
|
+ sed -i 's/^PrintMotd.*/PrintMotd no/' "$main_config"
|
|
|
+ else
|
|
|
+ echo "PrintMotd no" >> "$main_config"
|
|
|
+ fi
|
|
|
|
|
|
- # 4. Automate SSHD Config Settings
|
|
|
- echo -e "${C_BLUE}🔧 Configuring SSH Daemon (sshd_config)...${C_RESET}"
|
|
|
- local sshd_config="/etc/ssh/sshd_config"
|
|
|
+ # 5. Generate Initial Banners
|
|
|
+ update_all_user_banners
|
|
|
|
|
|
- if [ -f "$sshd_config" ]; then
|
|
|
- # Backup first
|
|
|
- cp "$sshd_config" "${sshd_config}.bak.$(date +%F_%T)" 2>/dev/null
|
|
|
-
|
|
|
- # 1. Clean previous configs we might have added
|
|
|
- sed -i '/ForceCommand \/usr\/local\/bin\/firewallfalcon-wrapper/d' "$sshd_config"
|
|
|
- sed -i '/Match User !root/d' "$sshd_config"
|
|
|
-
|
|
|
- # 2. Add the ForceCommand block at the END of the file
|
|
|
- # We match !root so we don't accidentally break the root VPS access
|
|
|
- echo "" >> "$sshd_config"
|
|
|
- echo "Match User !root" >> "$sshd_config"
|
|
|
- echo " ForceCommand /usr/local/bin/firewallfalcon-wrapper" >> "$sshd_config"
|
|
|
+ # 6. Cron Job for Daily Updates (At 00:01)
|
|
|
+ # We need a small separate script or command line to update banners
|
|
|
+ local updater_cmd="bash -c 'source $(realpath $0); update_all_user_banners'"
|
|
|
+ # Since we can't easily source this big script in cron, let's make a dedicated tiny updater
|
|
|
+ # OR simpler: Write the update logic to a small standalone script
|
|
|
+ local stand_alone_updater="/usr/local/bin/firewallfalcon-update-banners"
|
|
|
+
|
|
|
+ # We need to export the function logic to the file.
|
|
|
+ # We reconstruct the logic simply here to avoid complex variable passing.
|
|
|
+ cat > "$stand_alone_updater" <<EOF
|
|
|
+#!/bin/bash
|
|
|
+DB_FILE="/etc/firewallfalcon/users.db"
|
|
|
+BANNERS_DIR="/etc/firewallfalcon/banners"
|
|
|
+CONF_FILE="/etc/ssh/sshd_config.d/99-firewallfalcon-banners.conf"
|
|
|
+
|
|
|
+mkdir -p "\$BANNERS_DIR"
|
|
|
+echo "# Dynamic User Banners" > "\$CONF_FILE"
|
|
|
+
|
|
|
+if [[ -s "\$DB_FILE" ]]; then
|
|
|
+ while IFS=: read -r user pass expiry limit; do
|
|
|
+ current_ts=\$(date +%s)
|
|
|
+ expiry_ts=\$(date -d "\$expiry" +%s 2>/dev/null)
|
|
|
+ days_left="0"
|
|
|
+ status="EXPIRED"
|
|
|
|
|
|
- # 3. Disable PrintMotd/Banner globally to avoid clutter
|
|
|
- if grep -q "^PrintMotd" "$sshd_config"; then
|
|
|
- sed -i 's/^PrintMotd.*/PrintMotd no/' "$sshd_config"
|
|
|
- else
|
|
|
- sed -i '1i PrintMotd no' "$sshd_config"
|
|
|
+ if [ -n "\$expiry_ts" ]; then
|
|
|
+ diff=\$((expiry_ts - current_ts))
|
|
|
+ days_left=\$((diff / 86400))
|
|
|
+ if [ \$days_left -ge 0 ]; then status="ACTIVE"; fi
|
|
|
fi
|
|
|
- sed -i 's/^Banner /#Banner /' "$sshd_config"
|
|
|
-
|
|
|
- echo -e "${C_GREEN}✅ SSH Configuration updated with Wrapper.${C_RESET}"
|
|
|
|
|
|
- # Restart SSH to apply
|
|
|
- if systemctl is-active --quiet ssh; then
|
|
|
- systemctl restart ssh
|
|
|
- elif systemctl is-active --quiet sshd; then
|
|
|
- systemctl restart sshd
|
|
|
- fi
|
|
|
- else
|
|
|
- echo -e "${C_YELLOW}⚠️ /etc/ssh/sshd_config not found. Skipping SSH config update.${C_RESET}"
|
|
|
- fi
|
|
|
+ # Write Banner File
|
|
|
+ cat > "\$BANNERS_DIR/\$user" <<BANNER
|
|
|
+==================================================
|
|
|
+ 👋 Welcome, \$user
|
|
|
+ --------------------------------------------------
|
|
|
+ 📊 Status : \$status
|
|
|
+ ⏳ Days Left : \$days_left Days
|
|
|
+ 📅 Expires : \$expiry
|
|
|
+==================================================
|
|
|
+
|
|
|
+BANNER
|
|
|
+ # Append Config
|
|
|
+ echo "" >> "\$CONF_FILE"
|
|
|
+ echo "Match User \$user" >> "\$CONF_FILE"
|
|
|
+ echo " Banner \$BANNERS_DIR/\$user" >> "\$CONF_FILE"
|
|
|
+ done < "\$DB_FILE"
|
|
|
+fi
|
|
|
+
|
|
|
+if systemctl is-active --quiet ssh; then systemctl reload ssh;
|
|
|
+elif systemctl is-active --quiet sshd; then systemctl reload sshd; fi
|
|
|
+EOF
|
|
|
+ chmod +x "$stand_alone_updater"
|
|
|
+
|
|
|
+ # Add to Crontab
|
|
|
+ (crontab -l 2>/dev/null | grep -v "firewallfalcon-update-banners") | crontab -
|
|
|
+ (crontab -l 2>/dev/null; echo "1 0 * * * $stand_alone_updater") | crontab -
|
|
|
+
|
|
|
+ echo -e "${C_GREEN}✅ Native Dynamic Banners Configured.${C_RESET}"
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -2941,10 +3000,10 @@ main_menu() {
|
|
|
|
|
|
echo
|
|
|
echo -e " ${C_TITLE}════════════[ ${C_BOLD}⚙️ SYSTEM SETTINGS ${C_RESET}${C_TITLE}]═════════════${C_RESET}"
|
|
|
- printf " ${C_CHOICE}[%2s]${C_RESET} %-25s ${C_CHOICE}[%2s]${C_RESET} %-25s\n" "13" "CloudFlare Free Domain" "16" "Backup User Data"
|
|
|
- printf " ${C_CHOICE}[%2s]${C_RESET} %-25s ${C_CHOICE}[%2s]${C_RESET} %-25s\n" "15" "Auto-Reboot Task" "17" "Restore User Data"
|
|
|
- printf " ${C_CHOICE}[%2s]${C_RESET} %-25s ${C_CHOICE}[%2s]${C_RESET} %-25s\n" "18" "Cleanup Expired Users" ""
|
|
|
-
|
|
|
+ printf " ${C_CHOICE}[%2s]${C_RESET} %-25s ${C_CHOICE}[%2s]${C_RESET} %-25s\n" "13" "CloudFlare Free Domain" "16" "Restore User Data"
|
|
|
+ printf " ${C_CHOICE}[%2s]${C_RESET} %-25s ${C_CHOICE}[%2s]${C_RESET} %-25s\n" "14" "Auto-Reboot Task" "17" "Cleanup Expired Users"
|
|
|
+ printf " ${C_CHOICE}[%2s]${C_RESET} %-25s ${C_CHOICE}[%2s]${C_RESET} %-25s\n" "15" "Backup User Data" ""
|
|
|
+
|
|
|
echo
|
|
|
echo -e " ${C_DANGER}═══════════════════[ ${C_BOLD}🔥 DANGER ZONE ${C_RESET}${C_DANGER}]═══════════════════${C_RESET}"
|
|
|
echo -e " ${C_DANGER}[99]${C_RESET} Uninstall Script ${C_WARN}[ 0]${C_RESET} Exit"
|
|
|
@@ -2967,10 +3026,10 @@ main_menu() {
|
|
|
|
|
|
13) dns_menu; press_enter ;;
|
|
|
|
|
|
- 15) auto_reboot_menu ;;
|
|
|
- 16) backup_user_data; press_enter ;;
|
|
|
- 17) restore_user_data; press_enter ;;
|
|
|
- 18) cleanup_expired; press_enter ;;
|
|
|
+ 14) auto_reboot_menu ;;
|
|
|
+ 15) backup_user_data; press_enter ;;
|
|
|
+ 16) restore_user_data; press_enter ;;
|
|
|
+ 17) cleanup_expired; press_enter ;;
|
|
|
|
|
|
99) uninstall_script ;;
|
|
|
0) exit 0 ;;
|