#!/bin/bash # ============================================================================== # SFTP User Diagnostic Script # Use this script to diagnose SFTP/SSH account creation issues # ============================================================================== # Get username from argument or prompt if [ -z "$1" ]; then echo "Usage: $0 " echo "Example: $0 mightyuser1" exit 1 fi USERNAME="$1" echo "==============================================================================" echo "SFTP/SSH User Diagnostic Script" echo "Checking user: $USERNAME" echo "Timestamp: $(date)" echo "==============================================================================" echo # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Function to print colored output print_status() { local status=$1 local message=$2 if [ "$status" = "OK" ]; then echo -e "${GREEN}[OK]${NC} $message" elif [ "$status" = "ERROR" ]; then echo -e "${RED}[ERROR]${NC} $message" elif [ "$status" = "WARNING" ]; then echo -e "${YELLOW}[WARNING]${NC} $message" else echo "[INFO] $message" fi } echo "=== 1. USER ACCOUNT CHECK ===" if id "$USERNAME" &>/dev/null; then print_status "OK" "User account exists: $USERNAME" echo " User ID: $(id -u $USERNAME)" echo " Group ID: $(id -g $USERNAME)" echo " Groups: $(id -Gn $USERNAME)" echo " Home Directory: $(getent passwd $USERNAME | cut -d: -f6)" echo " Shell: $(getent passwd $USERNAME | cut -d: -f7)" else print_status "ERROR" "User account does NOT exist: $USERNAME" echo " Run: id $USERNAME" fi echo echo "=== 2. USER GROUPS CHECK ===" if id "$USERNAME" &>/dev/null; then # Get groups using id command - ensure we capture the output correctly GROUPS_OUTPUT=$(id -Gn "$USERNAME" 2>&1) GROUPS_EXIT=$? if [ $GROUPS_EXIT -eq 0 ] && [ -n "$GROUPS_OUTPUT" ]; then GROUPS_LIST="$GROUPS_OUTPUT" echo " All groups: $GROUPS_LIST" # Check for sftpusers or sshusers group if echo "$GROUPS_LIST" | grep -qw "sftpusers"; then print_status "OK" "User is in sftpusers group (SFTP-only access)" elif echo "$GROUPS_LIST" | grep -qw "sshusers"; then print_status "OK" "User is in sshusers group (SSH+SFTP access)" else print_status "ERROR" "User is NOT in sftpusers or sshusers group!" echo " Current groups: $GROUPS_LIST" echo " Fix: usermod -aG sftpusers $USERNAME (for SFTP-only)" echo " Fix: usermod -aG sshusers $USERNAME (for SSH+SFTP)" fi # Check for litespeed group if echo "$GROUPS_LIST" | grep -qw "litespeed"; then print_status "OK" "User is in litespeed group" else print_status "WARNING" "User is NOT in litespeed group (may affect file access)" fi else print_status "ERROR" "Failed to retrieve groups for user $USERNAME" echo " Command exit code: $GROUPS_EXIT" echo " Output: $GROUPS_OUTPUT" fi else print_status "ERROR" "User $USERNAME does not exist" fi echo echo "=== 3. HOME DIRECTORY CHECK ===" if id "$USERNAME" &>/dev/null; then USER_HOME=$(getent passwd $USERNAME | cut -d: -f6) if [ -d "$USER_HOME" ]; then print_status "OK" "Home directory exists: $USER_HOME" echo " Ownership: $(stat -c '%U:%G' $USER_HOME)" echo " Permissions: $(stat -c '%a' $USER_HOME)" # Check if home directory is owned by root (required for chroot) if [ "$(stat -c '%U' $USER_HOME)" = "root" ]; then print_status "OK" "Home directory is owned by root (required for chroot)" else print_status "ERROR" "Home directory must be owned by root for chroot!" echo " Fix: chown root:root $USER_HOME" fi # Check permissions PERMS=$(stat -c '%a' $USER_HOME) if [ "$PERMS" = "755" ] || [ "$PERMS" = "751" ]; then print_status "OK" "Home directory permissions are correct: $PERMS" else print_status "WARNING" "Home directory permissions should be 755 or 751, current: $PERMS" echo " Fix: chmod 755 $USER_HOME" fi else print_status "ERROR" "Home directory does NOT exist: $USER_HOME" fi fi echo echo "=== 4. DIRECTORY STRUCTURE CHECK ===" if id "$USERNAME" &>/dev/null; then USER_HOME=$(getent passwd $USERNAME | cut -d: -f6) if [ -d "$USER_HOME/data" ]; then print_status "OK" "Data directory exists: $USER_HOME/data" echo " Ownership: $(stat -c '%U:%G' $USER_HOME/data 2>/dev/null || echo 'N/A')" echo " Permissions: $(stat -c '%a' $USER_HOME/data 2>/dev/null || echo 'N/A')" if [ -d "$USER_HOME/data/ROOT" ]; then print_status "OK" "ROOT directory exists: $USER_HOME/data/ROOT" # Check if it's a mount point # mountpoint command is part of util-linux (installed by default on AlmaLinux 9.6) # Fallback to checking /proc/mounts if mountpoint is not available IS_MOUNTED=false if command -v mountpoint >/dev/null 2>&1; then if mountpoint -q "$USER_HOME/data/ROOT" 2>/dev/null; then IS_MOUNTED=true fi else # Fallback: check /proc/mounts if grep -q " $USER_HOME/data/ROOT " /proc/mounts 2>/dev/null; then IS_MOUNTED=true fi fi if [ "$IS_MOUNTED" = true ]; then print_status "OK" "ROOT is properly mounted (bind mount)" MOUNT_INFO=$(mount | grep "$USER_HOME/data/ROOT" 2>/dev/null || echo "No mount info found") echo " Mount info: $MOUNT_INFO" # Check webroot permissions WEBROOT_DIR="/var/www/webroot/ROOT" if [ -d "$WEBROOT_DIR" ]; then WEBROOT_PERMS=$(stat -c '%a' "$WEBROOT_DIR" 2>/dev/null) WEBROOT_GROUP=$(stat -c '%G' "$WEBROOT_DIR" 2>/dev/null) WEBROOT_OWNER=$(stat -c '%U:%G' "$WEBROOT_DIR" 2>/dev/null) echo " Webroot permissions: $WEBROOT_PERMS ($WEBROOT_OWNER)" # Check if group has write permission GROUP_WRITE_BIT=$(echo "$WEBROOT_PERMS" | cut -c2) if [ "$GROUP_WRITE_BIT" = "4" ] || [ "$GROUP_WRITE_BIT" = "5" ] || [ "$GROUP_WRITE_BIT" = "1" ] || [ "$GROUP_WRITE_BIT" = "0" ]; then print_status "WARNING" "Webroot does NOT have group write permissions (current: $WEBROOT_PERMS)" echo " Fix: chmod -R g+w $WEBROOT_DIR" else print_status "OK" "Webroot has group write permissions" fi if [ "$WEBROOT_GROUP" != "litespeed" ]; then print_status "WARNING" "Webroot group is not litespeed (current: $WEBROOT_GROUP)" echo " Fix: chgrp -R litespeed $WEBROOT_DIR" fi fi else print_status "WARNING" "ROOT directory exists but is not mounted" echo " Fix: mount --bind /var/www/webroot/ROOT $USER_HOME/data/ROOT" fi else print_status "ERROR" "ROOT directory does NOT exist: $USER_HOME/data/ROOT" fi else print_status "ERROR" "Data directory does NOT exist: $USER_HOME/data" fi fi echo echo "=== 5. PASSWORD CHECK ===" if id "$USERNAME" &>/dev/null; then # Check if password is set (this is tricky - we can only check if shadow entry exists) if grep -q "^$USERNAME:" /etc/shadow; then print_status "OK" "User has shadow entry (password record exists)" # Check if password field is empty or has '!' (locked) PWD_FIELD=$(grep "^$USERNAME:" /etc/shadow | cut -d: -f2) if [ -z "$PWD_FIELD" ] || [ "$PWD_FIELD" = "*" ] || [ "$PWD_FIELD" = "!" ]; then print_status "ERROR" "User password appears to be LOCKED or NOT SET!" echo " Password field: $PWD_FIELD" echo " Fix: echo '$USERNAME:NEW_PASSWORD' | chpasswd" else print_status "OK" "User password appears to be set (hashed)" fi else print_status "ERROR" "User does NOT have shadow entry!" fi fi echo echo "=== 6. SSH CONFIGURATION CHECK ===" echo "Checking SSH daemon configuration..." # Check if sshd_config.d directory exists and is included if [ -d "/etc/ssh/sshd_config.d" ]; then print_status "OK" "SSH config.d directory exists" if grep -q "^Include" /etc/ssh/sshd_config | grep -q "sshd_config.d"; then print_status "OK" "sshd_config.d is included in main config" else print_status "WARNING" "sshd_config.d may not be included (check Include directive)" fi else print_status "WARNING" "sshd_config.d directory does not exist" fi # Check addon config file ADDON_CONFIG="/etc/ssh/sshd_config.d/99-sftp-addon.conf" if [ -f "$ADDON_CONFIG" ]; then print_status "OK" "Addon config file exists: $ADDON_CONFIG" echo " Contents:" cat "$ADDON_CONFIG" | sed 's/^/ /' else print_status "WARNING" "Addon config file does NOT exist: $ADDON_CONFIG" fi # Check main sshd_config if grep -qE "^PasswordAuthentication\s+yes" /etc/ssh/sshd_config; then print_status "OK" "PasswordAuthentication is enabled in main config" elif grep -qE "^PasswordAuthentication\s+no" /etc/ssh/sshd_config; then print_status "ERROR" "PasswordAuthentication is DISABLED in main config!" echo " Fix: sed -i 's/^PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config" else print_status "WARNING" "PasswordAuthentication setting not found in main config (may use default)" fi # Check Match Group configuration if grep -q "Match Group sftpusers" /etc/ssh/sshd_config; then print_status "OK" "Match Group sftpusers found in main config" elif [ -f "$ADDON_CONFIG" ] && grep -q "Match Group sftpusers" "$ADDON_CONFIG"; then print_status "OK" "Match Group sftpusers found in addon config" else print_status "ERROR" "Match Group sftpusers NOT found in SSH config!" fi if grep -q "Match Group sshusers" /etc/ssh/sshd_config; then print_status "OK" "Match Group sshusers found in main config" elif [ -f "$ADDON_CONFIG" ] && grep -q "Match Group sshusers" "$ADDON_CONFIG"; then print_status "OK" "Match Group sshusers found in addon config" else print_status "WARNING" "Match Group sshusers NOT found (needed for SSH access)" fi # Test SSH config syntax if sshd -t 2>/dev/null; then print_status "OK" "SSH configuration syntax is valid" else print_status "ERROR" "SSH configuration syntax is INVALID!" echo " Run: sshd -t (as root) to see errors" fi echo echo "=== 7. SSH SERVICE STATUS ===" if systemctl is-active --quiet sshd; then print_status "OK" "SSH service is running" else print_status "ERROR" "SSH service is NOT running!" echo " Fix: systemctl start sshd" fi if systemctl is-enabled --quiet sshd; then print_status "OK" "SSH service is enabled (will start on boot)" else print_status "WARNING" "SSH service is NOT enabled" fi echo echo "=== 8. RECENT LOGS CHECK ===" LOG_DIR="/opt/add-sftp-user-addon/logs" if [ -d "$LOG_DIR" ]; then print_status "OK" "Log directory exists: $LOG_DIR" # Find user creation log USER_LOG=$(ls -t $LOG_DIR/user_creation-*.log 2>/dev/null | head -1) if [ -n "$USER_LOG" ]; then echo " Most recent user creation log: $USER_LOG" echo " Last 10 lines:" tail -10 "$USER_LOG" | sed 's/^/ /' else print_status "WARNING" "No user creation logs found" fi # Check error log if [ -f "$LOG_DIR/errors.log" ]; then ERROR_COUNT=$(wc -l < "$LOG_DIR/errors.log") if [ "$ERROR_COUNT" -gt 0 ]; then print_status "WARNING" "Found $ERROR_COUNT lines in error log" echo " Last 5 errors:" tail -5 "$LOG_DIR/errors.log" | sed 's/^/ /' fi fi else print_status "WARNING" "Log directory does not exist: $LOG_DIR" fi echo echo "=== 9. AUTHENTICATION TEST (SIMULATED) ===" if id "$USERNAME" &>/dev/null; then USER_SHELL=$(getent passwd $USERNAME | cut -d: -f7) AUTH_GROUPS_OUTPUT=$(id -Gn "$USERNAME" 2>&1) AUTH_GROUPS_EXIT=$? if [ $AUTH_GROUPS_EXIT -eq 0 ] && [ -n "$AUTH_GROUPS_OUTPUT" ]; then AUTH_GROUPS="$AUTH_GROUPS_OUTPUT" if [ "$USER_SHELL" = "/sbin/nologin" ]; then if echo "$AUTH_GROUPS" | grep -qw "sftpusers"; then print_status "OK" "User configured for SFTP-only (nologin shell + sftpusers group)" echo " Note: This user can ONLY use SFTP, not SSH shell access" else print_status "ERROR" "User has nologin shell but NOT in sftpusers group!" echo " Current groups: $AUTH_GROUPS" fi elif [ "$USER_SHELL" = "/bin/bash" ] || [ "$USER_SHELL" = "/bin/sh" ]; then if echo "$AUTH_GROUPS" | grep -qw "sshusers"; then print_status "OK" "User configured for SSH+SFTP (bash shell + sshusers group)" else print_status "ERROR" "User has bash shell but NOT in sshusers group!" echo " Current groups: $AUTH_GROUPS" echo " Fix: usermod -aG sshusers $USERNAME" fi else print_status "WARNING" "Unexpected shell: $USER_SHELL" fi else print_status "ERROR" "Failed to retrieve groups for authentication check" echo " Command exit code: $AUTH_GROUPS_EXIT" echo " Output: $AUTH_GROUPS_OUTPUT" fi else print_status "ERROR" "User $USERNAME does not exist" fi echo echo "=== 10. QUICK FIXES ===" echo "If user exists but login fails, try these commands (as root):" echo if id "$USERNAME" &>/dev/null; then echo "1. Reset password:" echo " echo '$USERNAME:NEW_PASSWORD' | chpasswd" echo echo "2. Fix group membership (choose one based on desired access):" echo " # For SFTP-only:" echo " usermod -aG sftpusers,litespeed $USERNAME" echo " usermod -s /sbin/nologin $USERNAME" echo " # For SSH+SFTP:" echo " usermod -aG sshusers,litespeed $USERNAME" echo " usermod -s /bin/bash $USERNAME" echo echo "3. Fix home directory permissions:" USER_HOME=$(getent passwd $USERNAME | cut -d: -f6) echo " chown root:root $USER_HOME" echo " chmod 755 $USER_HOME" echo echo "4. Remount ROOT directory:" echo " mount --bind /var/www/webroot/ROOT $USER_HOME/data/ROOT" echo echo "5. Restart SSH service:" echo " systemctl restart sshd" else echo "User does not exist. Cannot provide fixes." fi echo echo "==============================================================================" echo "Diagnostic complete!" echo "==============================================================================" # Exit with success status exit 0