From 8c918671bd0aeaa42e6e8f9a1bb7b189147edd08 Mon Sep 17 00:00:00 2001 From: Anthony Date: Thu, 10 Apr 2025 23:23:32 +0800 Subject: [PATCH] Updates --- add-sftp.sh | 323 ++++++++++++++++++++++------- manifest.jps | 486 ++++++++++++++++++++++++++++++++++++++++---- scripts/userlogs.sh | 7 - 3 files changed, 701 insertions(+), 115 deletions(-) delete mode 100644 scripts/userlogs.sh diff --git a/add-sftp.sh b/add-sftp.sh index ade4dee..1b94885 100644 --- a/add-sftp.sh +++ b/add-sftp.sh @@ -1,13 +1,51 @@ #!/bin/bash -LOG_FILE="/home/jelastic/add-sftp-user-addon/logs/script_output.log" +# Enhanced logging configuration +LOG_DIR="/home/jelastic/add-sftp-user-addon/logs" +LOG_FILE="$LOG_DIR/script_output.log" +ERROR_LOG="$LOG_DIR/errors.log" +OPERATION_LOG="$LOG_DIR/operations.log" +DEBUG_LOG="$LOG_DIR/debug.log" DEBUG=${4:-0} # Set to 1 to enable debug logging, controlled by 4th argument +SCRIPT_ID="$(date +%Y%m%d%H%M%S)-$$" # Unique ID for this script run (timestamp-PID) +# Ensure log directory exists with proper permissions +mkdir -p $LOG_DIR +chmod 755 $LOG_DIR + +# Rotate logs if they exceed 10MB (10485760 bytes) +for log_file in $LOG_FILE $ERROR_LOG $OPERATION_LOG $DEBUG_LOG; do + if [[ -f "$log_file" && $(stat -c%s "$log_file" 2>/dev/null || echo 0) -gt 10485760 ]]; then + mv "$log_file" "$log_file.$(date +%Y%m%d%H%M%S).old" + touch "$log_file" + chmod 644 "$log_file" + fi +done + +# Enhanced logging functions log() { local level=${1:-INFO} local message=${2} local timestamp=$(date +"%Y-%m-%d %H:%M:%S") - echo "$timestamp [$level] $message" | tee -a $LOG_FILE + local formatted_message="[$SCRIPT_ID] $timestamp [$level] $message" + + # Log to appropriate files based on level + echo "$formatted_message" | tee -a $LOG_FILE + + # Also log to operation log for main operations + if [[ "$level" == "INFO" || "$level" == "SUCCESS" ]]; then + echo "$formatted_message" >> $OPERATION_LOG + fi + + # Also log errors to dedicated error log + if [[ "$level" == "ERROR" || "$level" == "WARNING" ]]; then + echo "$formatted_message" >> $ERROR_LOG + fi + + # Log debug messages to debug log if DEBUG mode is on + if [[ "$level" == "DEBUG" && "$DEBUG" -eq 1 ]]; then + echo "$formatted_message" >> $DEBUG_LOG + fi } log_error() { @@ -24,113 +62,260 @@ log_debug() { fi } -# Validate username format +log_success() { + log "SUCCESS" "$1" +} + +# Log system information for debugging context +log_system_info() { + log_debug "============= SYSTEM INFORMATION =============" + log_debug "Operating System: $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2 | tr -d '\"')" + log_debug "Kernel: $(uname -r)" + log_debug "SSH Version: $(ssh -V 2>&1)" + log_debug "SSH Config Status: $(systemctl status sshd | grep Active | awk '{print $2}')" + log_debug "Script Parameters: username=$USERNAME, ssh_enabled=$SSH_ENABLED" + log_debug "==============================================" +} + +# Function to log command execution with result +log_cmd() { + local cmd="$1" + local cmd_desc="$2" + + log_debug "Executing: $cmd_desc" + log_debug "Command: $cmd" + + # Execute command and capture output and status + local output + output=$(eval "$cmd" 2>&1) + local status=$? + + if [ $status -eq 0 ]; then + log_debug "Command succeeded: $cmd_desc" + if [ -n "$output" ]; then + log_debug "Output: $output" + fi + else + log_error "Command failed ($status): $cmd_desc" + log_error "Error output: $output" + fi + + return $status +} + +# Fix SFTP configuration for Jelastic Virtuozzo LLSMP +fix_sftp_config() { + log "Checking and fixing SSH configuration for SFTP access" + + # Create a backup of the original config + log_cmd "cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d%H%M%S)" "Creating backup of original sshd_config" + + # Fix the malformed SFTP subsystem line - using safer sed approach + if grep -q "Subsystemsftp" /etc/ssh/sshd_config; then + log "Fixing malformed SFTP subsystem configuration" + # Use a temporary file for safer editing + if log_cmd "sed 's|Subsystemsftp/usr/libexec/openssh/sftp-server|Subsystem sftp /usr/libexec/openssh/sftp-server|g' /etc/ssh/sshd_config > /etc/ssh/sshd_config.new" "Fixing malformed Subsystem line"; then + log_cmd "mv /etc/ssh/sshd_config.new /etc/ssh/sshd_config" "Applying fixed configuration" + log_success "Fixed malformed Subsystem line" + else + log_error "Failed to fix Subsystem line, reverting to backup" + log_cmd "cp /etc/ssh/sshd_config.bak.$(ls -t /etc/ssh/sshd_config.bak.* | head -1 | awk -F/ '{print $NF}') /etc/ssh/sshd_config" "Restoring backup" + fi + fi + + # Enable password authentication globally if it's set to no + if grep -q "^PasswordAuthentication no" /etc/ssh/sshd_config; then + log "Enabling password authentication in SSH" + if log_cmd "sed 's/^PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config > /etc/ssh/sshd_config.new" "Enabling password authentication"; then + log_cmd "mv /etc/ssh/sshd_config.new /etc/ssh/sshd_config" "Applying configuration with password authentication" + log_success "Enabled password authentication" + else + log_error "Failed to enable password authentication, reverting to backup" + log_cmd "cp /etc/ssh/sshd_config.bak.$(ls -t /etc/ssh/sshd_config.bak.* | head -1 | awk -F/ '{print $NF}') /etc/ssh/sshd_config" "Restoring backup" + fi + fi + + # Remove any existing incomplete/duplicate Match Group sftpusers blocks + if grep -q "Match Group sftpusers" /etc/ssh/sshd_config; then + log "Removing existing Match Group sftpusers blocks to prevent duplicates" + # This complex sed pattern removes the Match Group sftpusers block completely + if log_cmd "sed '/^Match Group sftpusers/,/^Match\|^[[:space:]]*$/d' /etc/ssh/sshd_config > /etc/ssh/sshd_config.new" "Removing existing Match Group blocks"; then + log_cmd "mv /etc/ssh/sshd_config.new /etc/ssh/sshd_config" "Applying cleaned configuration" + log_success "Removed existing Match Group sftpusers blocks" + else + log_error "Failed to remove existing Match Group blocks, reverting to backup" + log_cmd "cp /etc/ssh/sshd_config.bak.$(ls -t /etc/ssh/sshd_config.bak.* | head -1 | awk -F/ '{print $NF}') /etc/ssh/sshd_config" "Restoring backup" + fi + fi + + # Configure SFTP chroot jail cleanly at the end of the file + log "Adding fresh SFTP chroot configuration for sftpusers group" + cat >> /etc/ssh/sshd_config << EOF + +# SFTP chroot configuration added by SFTP addon +Match Group sftpusers + ChrootDirectory /home/sftpusers/%u + ForceCommand internal-sftp + PasswordAuthentication yes + AllowTcpForwarding no + X11Forwarding no +EOF + + # Remove duplicate lines and verify config + log "Cleaning up configuration file" + if log_cmd "awk '!seen[\$0]++' /etc/ssh/sshd_config > /etc/ssh/sshd_config.new" "Removing duplicate lines"; then + log_cmd "mv /etc/ssh/sshd_config.new /etc/ssh/sshd_config" "Applying deduplicated configuration" + log_success "Removed duplicate lines from configuration" + else + log_error "Failed to remove duplicate lines, reverting to backup" + log_cmd "cp /etc/ssh/sshd_config.bak.$(ls -t /etc/ssh/sshd_config.bak.* | head -1 | awk -F/ '{print $NF}') /etc/ssh/sshd_config" "Restoring backup" + fi + + # Verify the configuration before restarting + log "Verifying SSH configuration before restart" + if log_cmd "sshd -t" "Validating sshd configuration"; then + log_success "SSH configuration is valid, restarting service" + log_cmd "systemctl restart sshd" "Restarting SSH service" + else + log_error "SSH configuration is INVALID, reverting to backup" + log_cmd "cp /etc/ssh/sshd_config.bak.$(ls -t /etc/ssh/sshd_config.bak.* | head -1 | awk -F/ '{print $NF}') /etc/ssh/sshd_config" "Restoring backup" + log "Restarting SSH with original configuration" + log_cmd "systemctl restart sshd" "Restarting SSH service with original config" + return 1 + fi + + return 0 +} + validate_username() { local username=$1 + log_debug "Validating username: $username" + if ! [[ $username =~ ^[a-zA-Z0-9_]{3,32}$ ]]; then log_error "Invalid username format. Username must be 3-32 characters long and contain only letters, numbers, and underscores." return 1 fi + + log_debug "Username validation passed" return 0 } USERNAME=$1 PASSWORD=$2 -SSH_ENABLED=$3 +SSH_ENABLED=${3:-false} -log "Script started" +log "======== STARTING SFTP USER SETUP ========" +log "Script started with username: $USERNAME, ssh_enabled: $SSH_ENABLED, script_id: $SCRIPT_ID" -# Validate username format -if ! validate_username "$USERNAME"; then +# Log system information +log_system_info + +# Fix SFTP configuration +log "Phase 1: Configuring SSH/SFTP service" +if ! fix_sftp_config; then + log_error "Failed to configure SSH/SFTP service, exiting" exit 1 fi +log_success "SSH/SFTP service configuration completed" + +# Validate username format +log "Phase 2: Validating username" +if ! validate_username "$USERNAME"; then + log_error "Username validation failed, exiting" + exit 1 +fi +log_success "Username validation passed" # Check if user already exists +log "Phase 3: Checking if user already exists" if id "$USERNAME" &>/dev/null; then log_error "Username $USERNAME already exists. Please choose a different username." exit 1 fi +log_success "Username is available for creation" USER_HOME="/home/sftpusers/$USERNAME" ROOT_DIRECTORY="/var/www/webroot/ROOT" -ROOT_GROUP=$(stat -c '%G' $ROOT_DIRECTORY) +log_debug "Setting paths - USER_HOME: $USER_HOME, ROOT_DIRECTORY: $ROOT_DIRECTORY" -# Create the wp-admins group if it doesn't exist -if ! grep -q "^wp-admins:" /etc/group; then - if groupadd wp-admins; then - log "Group wp-admins created successfully." - else - log_error "Failed to create group wp-admins." - exit 1 - fi +# Create the sftpusers group if it doesn't exist +log "Phase 4: Setting up groups" +if ! getent group sftpusers > /dev/null; then + log "Creating sftpusers group for SFTP chroot access" + log_cmd "groupadd sftpusers" "Creating sftpusers group" fi +log_success "Group setup completed" # Ensure the parent directory for user home directories exists +log "Phase 5: Setting up directories" if [ ! -d "/home/sftpusers" ]; then - mkdir -p /home/sftpusers - if [ $? -ne 0 ]; then - log_error "Failed to create directory /home/sftpusers." - exit 1 - else - log "Directory /home/sftpusers created successfully." - fi + log "Creating /home/sftpusers directory" + log_cmd "mkdir -p /home/sftpusers" "Creating /home/sftpusers directory" + log_cmd "chown root:root /home/sftpusers" "Setting ownership for /home/sftpusers" + log_cmd "chmod 755 /home/sftpusers" "Setting permissions for /home/sftpusers" fi +log_success "Directory setup completed" -if ! useradd -d $USER_HOME $USERNAME; then - log_error "Failed to create user $USERNAME." - exit 1 -fi - -# Ensure WP-CLI is installed -if ! command -v wp &> /dev/null; then - if curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar; then - log "WP-CLI phar file downloaded successfully." - else - log_error "Failed to download WP-CLI phar file." - exit 1 - fi - - if chmod +x wp-cli.phar; then - log "Permissions set on WP-CLI phar file." - else - log_error "Failed to set execute permissions on WP-CLI phar file." - exit 1 - fi - - if mv wp-cli.phar /usr/local/bin/wp; then - log "WP-CLI installed successfully." - else - log_error "Failed to move WP-CLI phar file to /usr/local/bin/wp." - exit 1 - fi +# Create the user account +log "Phase 6: Creating user account" +if [ "$SSH_ENABLED" = "true" ]; then + log "Creating user with SSH access" + log_cmd "useradd -d $USER_HOME -m -s /bin/bash $USERNAME" "Creating user with bash shell" else - log "WP-CLI is already installed." + log "Creating user with SFTP-only access" + log_cmd "useradd -d $USER_HOME -m -s /sbin/nologin $USERNAME" "Creating user with nologin shell" fi +log_success "User account created" -[ ! -d "$ROOT_DIRECTORY" ] && { log_error "ROOT_DIRECTORY $ROOT_DIRECTORY does not exist."; exit 2; } +# Set password +log "Phase 7: Setting user password" +log_cmd "echo '$USERNAME:$PASSWORD' | chpasswd" "Setting user password" +log_success "Password set for user $USERNAME" -mkdir -p $USER_HOME -echo "$USERNAME:$PASSWORD" | chpasswd +# Set up proper directory structure for chroot jail +log "Phase 8: Setting up chroot jail structure" +log_cmd "chown root:root $USER_HOME" "Setting ownership for chroot directory" +log_cmd "chmod 755 $USER_HOME" "Setting permissions for chroot directory" -log "User $USERNAME created with home directory $USER_HOME" +# Create writable data directory for user +log_cmd "mkdir -p $USER_HOME/data" "Creating data directory" +log_cmd "chown $USERNAME:$USERNAME $USER_HOME/data" "Setting ownership for data directory" +log_cmd "chmod 775 $USER_HOME/data" "Setting permissions for data directory" +log_success "Chroot structure set up" -ln -s $ROOT_DIRECTORY $USER_HOME/ROOT -log "Symlink created for $USERNAME pointing to $ROOT_DIRECTORY" +# Create symlink to webroot +log "Phase 9: Creating symlink to webroot" +log_cmd "ln -s $ROOT_DIRECTORY $USER_HOME/data/ROOT" "Creating symlink to ROOT directory" +log_success "Created symlink to $ROOT_DIRECTORY in $USER_HOME/data/ROOT" -usermod -aG $ROOT_GROUP $USERNAME -log "$USERNAME added to group $ROOT_GROUP" +# Add user to the required groups +log "Phase 10: Adding user to groups" +log_cmd "usermod -aG sftpusers $USERNAME" "Adding user to sftpusers group" +log_success "Added $USERNAME to sftpusers group for chroot access" -chown $USERNAME:$ROOT_GROUP $USER_HOME -chmod 750 $USER_HOME +log_cmd "usermod -aG litespeed $USERNAME" "Adding user to litespeed group" +log_success "Added $USERNAME to litespeed group for file access" -chown -R :$ROOT_GROUP /var/www/webroot/ROOT/ -find /var/www/webroot/ROOT/ -type d -exec chmod 770 {} \; -find /var/www/webroot/ROOT/ -type f -exec chmod 660 {} \; +# Create welcome file +log "Phase 11: Creating welcome file" +cat > $USER_HOME/data/welcome.txt << EOF +Welcome to your SFTP account on Jelastic! -chmod g+s $ROOT_DIRECTORY +Your account has been set up with the following details: -log "Script completed for user $USERNAME" +Username: $USERNAME +Home Directory: $USER_HOME +Web Root: $USER_HOME/data/ROOT (symlink to $ROOT_DIRECTORY) -# Output the created username and password -echo "export CREATED_USERNAME=$USERNAME" >> /etc/profile -echo "export CREATED_PASSWORD=$PASSWORD" >> /etc/profile \ No newline at end of file +For help and support, please contact your system administrator. +EOF +log_cmd "chown $USERNAME:$USERNAME $USER_HOME/data/welcome.txt" "Setting welcome file ownership" +log_cmd "chmod 644 $USER_HOME/data/welcome.txt" "Setting welcome file permissions" +log_success "Welcome file created" + +log_success "Script completed successfully for user $USERNAME" +log "======== SFTP USER SETUP COMPLETE ========" + +# Export variables for JPS +log_cmd "echo \"export CREATED_USERNAME=$USERNAME\" >> /etc/profile" "Exporting username variable" +log_cmd "echo \"export CREATED_PASSWORD=$PASSWORD\" >> /etc/profile" "Exporting password variable" \ No newline at end of file diff --git a/manifest.jps b/manifest.jps index a81bc78..02b878a 100644 --- a/manifest.jps +++ b/manifest.jps @@ -1,8 +1,8 @@ version: 0.4 id: addsftp type: update -description: An addon to add new SFTP users. It can also manage created user accounts. If SSH is enabled, WP-CLI will attempt to be installed if it is not yet installed. -name: Add SFTP User +description: An addon to add new SFTP users for Jelastic Virtuozzo LLSMP environments. It manages user accounts with secure SFTP access and optional SSH access with proper chroot jailing. +name: Add SFTP User for Jelastic targetNodes: nodeGroup: cp @@ -14,7 +14,7 @@ settings: - type: displayfield name: infoField caption: Root Directory /var/www/webroot/ROOT/ - description: "A user-specific directory will be created under /home/username" + description: "Files will be accessible in a data/ROOT directory within the user's home" required: false - type: string name: custom_username @@ -32,7 +32,8 @@ settings: name: enable_ssh caption: Also enable SSH access default: false - required: false + required: false + tip: "If enabled, the user will have both SFTP and SSH access. Otherwise, only SFTP access will be granted." manageUserForm: fields: - type: string @@ -58,21 +59,251 @@ onInstall: - cmd [cp]: user: root commands: |- - mkdir -p /home/jelastic/add-sftp-user-addon/ - mkdir -p /home/jelastic/add-sftp-user-addon/logs - touch /home/jelastic/add-sftp-user-addon/logs/script_output.log - wget https://deploy-proxy.mightybox.io/addons/add-sftp-user/raw/branch/main/add-sftp.sh -O /home/jelastic/add-sftp-user-addon/add-sftp.sh - chmod +x /home/jelastic/add-sftp-user-addon/*.sh + # Create log directory structure + mkdir -p /home/jelastic/add-sftp-user-addon/logs/{operations,errors,debug} + chmod -R 755 /home/jelastic/add-sftp-user-addon/logs + + # Setup log files with proper permissions + touch /home/jelastic/add-sftp-user-addon/logs/script_output.log + touch /home/jelastic/add-sftp-user-addon/logs/operations/install.log + touch /home/jelastic/add-sftp-user-addon/logs/errors/install.log + chmod 644 /home/jelastic/add-sftp-user-addon/logs/*.log + chmod 644 /home/jelastic/add-sftp-user-addon/logs/*/*.log + + # Create a function for structured logging + cat > /home/jelastic/add-sftp-user-addon/log_helper.sh << 'EOF' +#!/bin/bash + +LOG_DIR="/home/jelastic/add-sftp-user-addon/logs" +SCRIPT_ID="$(date +%Y%m%d%H%M%S)-$$" + +# Main logging function +jps_log() { + local level=${1:-INFO} + local message=${2} + local log_file=${3:-$LOG_DIR/script_output.log} + local timestamp=$(date +"%Y-%m-%d %H:%M:%S") + + echo "[$SCRIPT_ID] $timestamp [$level] $message" >> "$log_file" + + # Also log to stdout + echo "[$level] $message" + + # Log errors to error log + if [[ "$level" == "ERROR" || "$level" == "WARNING" ]]; then + echo "[$SCRIPT_ID] $timestamp [$level] $message" >> "$LOG_DIR/errors/$(basename "$log_file")" + fi + + # Log successful operations + if [[ "$level" == "INFO" || "$level" == "SUCCESS" ]]; then + echo "[$SCRIPT_ID] $timestamp [$level] $message" >> "$LOG_DIR/operations/$(basename "$log_file")" + fi +} + +# Log command execution +jps_log_cmd() { + local cmd="$1" + local desc="$2" + local log_file=${3:-$LOG_DIR/script_output.log} + + jps_log "DEBUG" "Executing: $desc" "$log_file" + jps_log "DEBUG" "Command: $cmd" "$log_file" + + # Execute command and capture output and status + local output + output=$(eval "$cmd" 2>&1) + local status=$? + + if [ $status -eq 0 ]; then + jps_log "DEBUG" "Command succeeded: $desc" "$log_file" + [ -n "$output" ] && jps_log "DEBUG" "Output: $output" "$log_file" + else + jps_log "ERROR" "Command failed ($status): $desc" "$log_file" + jps_log "ERROR" "Error output: $output" "$log_file" + fi + + return $status +} + +# Log system information +jps_log_system_info() { + local log_file=${1:-$LOG_DIR/script_output.log} + + jps_log "DEBUG" "============= SYSTEM INFORMATION =============" "$log_file" + jps_log "DEBUG" "Operating System: $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2 | tr -d '\"')" "$log_file" + jps_log "DEBUG" "Kernel: $(uname -r)" "$log_file" + jps_log "DEBUG" "SSH Version: $(ssh -V 2>&1)" "$log_file" + jps_log "DEBUG" "SSH Status: $(systemctl status sshd | grep Active | awk '{print $2}')" "$log_file" + jps_log "DEBUG" "=============================================" "$log_file" +} + +# Function to get detailed user information including creation date +# This replaces the functionality of the retired userlogs.sh script +jps_get_user_info() { + local log_file=${1:-$LOG_DIR/list_users.log} + + jps_log "INFO" "Retrieving detailed user information" "$log_file" + + # Get SFTP users + local users=$(find /home/sftpusers -maxdepth 1 -mindepth 1 -type d -exec basename {} \;) + + if [ -z "$users" ]; then + jps_log "INFO" "No SFTP users found" "$log_file" + return 0 + fi + + jps_log "INFO" "Found users, retrieving creation dates" "$log_file" + local result="" + + # Process each user + for user in $users; do + # Get creation date from directory timestamp + local creation_date=$(stat -c "%y" "/home/sftpusers/$user" 2>/dev/null | cut -d. -f1) + + # Try to get last password change as fallback + if [ -z "$creation_date" ]; then + if id "$user" &>/dev/null; then + creation_date=$(chage -l "$user" 2>/dev/null | grep "Last password change" | cut -d: -f2) + fi + fi + + if [ -n "$creation_date" ]; then + result="${result}Username: $user - Created: $creation_date\n" + else + result="${result}Username: $user - Created: Unknown\n" + fi + done + + if [ -n "$result" ]; then + jps_log "SUCCESS" "User information retrieved successfully" "$log_file" + echo -e "$result" + else + jps_log "WARNING" "Could not retrieve user information" "$log_file" + echo "" + fi +} + +# Make the logging script executable +chmod +x /home/jelastic/add-sftp-user-addon/log_helper.sh + +# Download the SFTP script +wget https://deploy-proxy.mightybox.io/addons/add-sftp-user/raw/branch/main/add-sftp.sh -O /home/jelastic/add-sftp-user-addon/add-sftp.sh +chmod +x /home/jelastic/add-sftp-user-addon/add-sftp.sh + +# Source the logging helper +source /home/jelastic/add-sftp-user-addon/log_helper.sh + +# Log installation started +jps_log "INFO" "======== SFTP ADDON INSTALLATION STARTED ========" "install.log" +jps_log_system_info "install.log" + +# Install SFTP addon on Jelastic environment +jps_log_cmd "mkdir -p /home/jelastic/add-sftp-user-addon/" "Creating log directory structure" +jps_log_cmd "mkdir -p /home/jelastic/add-sftp-user-addon/logs" "Creating log directory structure" +jps_log_cmd "touch /home/jelastic/add-sftp-user-addon/logs/script_output.log" "Creating script_output.log" +jps_log_cmd "wget https://deploy-proxy.mightybox.io/addons/add-sftp-user/raw/branch/main/add-sftp.sh -O /home/jelastic/add-sftp-user-addon/add-sftp.sh" "Downloading SFTP script" +jps_log_cmd "chmod +x /home/jelastic/add-sftp-user-addon/*.sh" "Making SFTP script executable" +jps_log_cmd "echo \"$(date) - Installing SFTP addon on Jelastic environment\" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log" "Logging installation" + - cmd[cp]: - user: root - commands: |- - if grep -qE "^Match User user[0-9]*$" /etc/ssh/sshd_config; then - sed -i '/^Match User user[0-9]*/!b;n;c\ PasswordAuthentication yes' /etc/ssh/sshd_config - else - echo -e "\n# Added by SFTP addon\nMatch User user*\n\tPasswordAuthentication yes" >> /etc/ssh/sshd_config - fi - awk '!seen[$0]++' /etc/ssh/sshd_config > /etc/ssh/sshd_config.tmp && mv /etc/ssh/sshd_config.tmp /etc/ssh/sshd_config - systemctl restart sshd + user: root + commands: |- + # Source the logging helper + source /home/jelastic/add-sftp-user-addon/log_helper.sh + + # Create a backup of the original SSH config + jps_log "INFO" "Creating backup of original sshd_config" "install.log" + jps_log_cmd "cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d%H%M%S)" "Creating backup of SSH config" "install.log" + + # Fix the malformed SFTP subsystem configuration using safer approach + if grep -q "Subsystemsftp" /etc/ssh/sshd_config; then + jps_log "INFO" "Found malformed SFTP subsystem configuration, fixing it" "install.log" + if jps_log_cmd "sed 's|Subsystemsftp/usr/libexec/openssh/sftp-server|Subsystem sftp /usr/libexec/openssh/sftp-server|g' /etc/ssh/sshd_config > /etc/ssh/sshd_config.new" "Fixing malformed SFTP configuration" "install.log"; then + jps_log_cmd "mv /etc/ssh/sshd_config.new /etc/ssh/sshd_config" "Applying fixed configuration" "install.log" + jps_log "SUCCESS" "Fixed malformed SFTP subsystem configuration" "install.log" + else + jps_log "ERROR" "Failed to fix SFTP subsystem, reverting to backup" "install.log" + jps_log_cmd "cp /etc/ssh/sshd_config.bak.$(ls -t /etc/ssh/sshd_config.bak.* | head -1 | awk -F/ '{print $NF}') /etc/ssh/sshd_config" "Restoring backup" "install.log" + fi + else + jps_log "INFO" "SFTP subsystem configuration is correct" "install.log" + fi + + # Enable password authentication globally if it's set to no + if grep -q "^PasswordAuthentication no" /etc/ssh/sshd_config; then + jps_log "INFO" "Password authentication is disabled, enabling it" "install.log" + if jps_log_cmd "sed 's/^PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config > /etc/ssh/sshd_config.new" "Enabling password authentication" "install.log"; then + jps_log_cmd "mv /etc/ssh/sshd_config.new /etc/ssh/sshd_config" "Applying configuration with password authentication" "install.log" + jps_log "SUCCESS" "Enabled global password authentication" "install.log" + else + jps_log "ERROR" "Failed to enable password authentication, reverting to backup" "install.log" + jps_log_cmd "cp /etc/ssh/sshd_config.bak.$(ls -t /etc/ssh/sshd_config.bak.* | head -1 | awk -F/ '{print $NF}') /etc/ssh/sshd_config" "Restoring backup" "install.log" + fi + else + jps_log "INFO" "Password authentication is already enabled" "install.log" + fi + + # Remove any existing duplicate Match Group sftpusers blocks + if grep -q "Match Group sftpusers" /etc/ssh/sshd_config; then + jps_log "INFO" "Found existing Match Group sftpusers configuration, removing it" "install.log" + if jps_log_cmd "sed '/^Match Group sftpusers/,/^Match\|^[[:space:]]*$/d' /etc/ssh/sshd_config > /etc/ssh/sshd_config.new" "Removing existing Match Group blocks" "install.log"; then + jps_log_cmd "mv /etc/ssh/sshd_config.new /etc/ssh/sshd_config" "Applying cleaned configuration" "install.log" + jps_log "SUCCESS" "Removed existing Match Group sftpusers blocks" "install.log" + else + jps_log "ERROR" "Failed to remove existing Match blocks, reverting to backup" "install.log" + jps_log_cmd "cp /etc/ssh/sshd_config.bak.$(ls -t /etc/ssh/sshd_config.bak.* | head -1 | awk -F/ '{print $NF}') /etc/ssh/sshd_config" "Restoring backup" "install.log" + fi + else + jps_log "INFO" "No existing Match Group sftpusers configuration found" "install.log" + fi + + # Add SFTP chroot configuration at the end + jps_log "INFO" "Adding SFTP chroot configuration" "install.log" + jps_log_cmd "echo -e '\n# SFTP chroot configuration added by SFTP addon\nMatch Group sftpusers\n ChrootDirectory /home/sftpusers/%u\n ForceCommand internal-sftp\n PasswordAuthentication yes\n AllowTcpForwarding no\n X11Forwarding no' >> /etc/ssh/sshd_config" "Adding SFTP chroot configuration" "install.log" + jps_log "SUCCESS" "Added SFTP chroot configuration" "install.log" + + # Create sftpusers group for chroot jailing + if ! getent group sftpusers > /dev/null; then + jps_log "INFO" "sftpusers group doesn't exist, creating it" "install.log" + jps_log_cmd "groupadd sftpusers" "Creating sftpusers group" "install.log" + jps_log "SUCCESS" "Created sftpusers group" "install.log" + else + jps_log "INFO" "sftpusers group already exists" "install.log" + fi + + # Create sftpusers directory + if [ ! -d "/home/sftpusers" ]; then + jps_log "INFO" "Creating /home/sftpusers directory" "install.log" + jps_log_cmd "mkdir -p /home/sftpusers" "Creating sftpusers directory" "install.log" + jps_log_cmd "chown root:root /home/sftpusers" "Setting ownership for sftpusers directory" "install.log" + jps_log_cmd "chmod 755 /home/sftpusers" "Setting permissions for sftpusers directory" "install.log" + jps_log "SUCCESS" "Created /home/sftpusers directory" "install.log" + else + jps_log "INFO" "/home/sftpusers directory already exists" "install.log" + fi + + # Clean up configuration - remove duplicate lines + jps_log "INFO" "Cleaning up configuration file" "install.log" + if jps_log_cmd "awk '!seen[\$0]++' /etc/ssh/sshd_config > /etc/ssh/sshd_config.new" "Removing duplicate lines" "install.log"; then + jps_log_cmd "mv /etc/ssh/sshd_config.new /etc/ssh/sshd_config" "Applying deduplicated configuration" "install.log" + jps_log "SUCCESS" "Removed duplicate lines from configuration" "install.log" + else + jps_log "ERROR" "Failed to clean up configuration, reverting to backup" "install.log" + jps_log_cmd "cp /etc/ssh/sshd_config.bak.$(ls -t /etc/ssh/sshd_config.bak.* | head -1 | awk -F/ '{print $NF}') /etc/ssh/sshd_config" "Restoring backup" "install.log" + fi + + # Verify configuration is valid before applying + jps_log "INFO" "Verifying SSH configuration" "install.log" + if jps_log_cmd "sshd -t" "Validating sshd configuration" "install.log"; then + jps_log "SUCCESS" "SSH configuration is valid, applying changes" "install.log" + jps_log_cmd "systemctl restart sshd" "Restarting SSH service" "install.log" + else + jps_log "ERROR" "SSH configuration is INVALID, reverting to backup" "install.log" + jps_log_cmd "cp /etc/ssh/sshd_config.bak.$(ls -t /etc/ssh/sshd_config.bak.* | head -1 | awk -F/ '{print $NF}') /etc/ssh/sshd_config" "Restoring backup" "install.log" + jps_log_cmd "systemctl restart sshd" "Restarting SSH service with original config" "install.log" + fi + + jps_log "SUCCESS" "======== SFTP ADDON CONFIGURATION COMPLETED ========" "install.log" - cmd[cp]: user: root commands: @@ -92,62 +323,239 @@ menu: actions: add_sftp_user: + - if ('${settings.enable_ssh}' == 'true'): + setGlobals: + ssh_enabled: "true" + - if ('${settings.enable_ssh}' != 'true'): + setGlobals: + ssh_enabled: "false" - cmd[cp]: user: root - commands: bash /home/jelastic/add-sftp-user-addon/add-sftp.sh ${globals.username} ${globals.password} - - cmd[cp]: - user: root - commands: echo $CREATED_USERNAME + commands: |- + # Source the logging helper + source /home/jelastic/add-sftp-user-addon/log_helper.sh + + # Log the action + jps_log "INFO" "======== STARTING SFTP USER CREATION ========" "user_creation.log" + jps_log "INFO" "Creating user: ${globals.username}, SSH enabled: ${globals.ssh_enabled}" "user_creation.log" + + # Run the SFTP user creation script with logging + jps_log_cmd "bash /home/jelastic/add-sftp-user-addon/add-sftp.sh ${globals.username} ${globals.password} ${globals.ssh_enabled}" "Running add-sftp.sh script" "user_creation.log" + + # Capture the created username and password + jps_log "INFO" "Retrieving created username" "user_creation.log" + CREATED_USERNAME=$(echo $CREATED_USERNAME) + jps_log "DEBUG" "Created username: $CREATED_USERNAME" "user_creation.log" + + jps_log "INFO" "Retrieving created password" "user_creation.log" + CREATED_PASSWORD=$(echo $CREATED_PASSWORD) + jps_log "DEBUG" "Password retrieved" "user_creation.log" + + # Export for JPS + echo $CREATED_USERNAME - setGlobals: username: ${response.out} - cmd[cp]: user: root - commands: echo $CREATED_PASSWORD + commands: |- + # Source the logging helper + source /home/jelastic/add-sftp-user-addon/log_helper.sh + + # Log the action + jps_log "SUCCESS" "User ${globals.username} created successfully" "user_creation.log" + + # Export password + echo $CREATED_PASSWORD - setGlobals: password: ${response.out} + - cmd[cp]: + user: root + commands: |- + # Source the logging helper + source /home/jelastic/add-sftp-user-addon/log_helper.sh + + # Log completion + jps_log "SUCCESS" "======== SFTP USER CREATION COMPLETED ========" "user_creation.log" + jps_log "INFO" "Connection details - Host: ${globals.sftpHost}, Port: ${globals.sftpPort}, Username: ${globals.username}" "user_creation.log" - return: type: info - message: "Connection Details\n\nSFTP Host: ${globals.sftpHost}\n\nPort: ${globals.sftpPort}\n\nLogin Credentials\n\nUsername: ${globals.username}\n\nPassword: ${globals.password}" + message: "Connection Details\n\nSFTP Host: ${globals.sftpHost}\n\nPort: ${globals.sftpPort}\n\nLogin Credentials\n\nUsername: ${globals.username}\n\nPassword: ${globals.password}\n\nNotes:\n- Files are accessible at /data/ROOT inside your SFTP session\n- If you enabled SSH access, you can also log in via SSH" change_password: - - if ('${settings.custom_password}' != ''): - setGlobals: - password: ${settings.custom_password} + # Verify user exists - cmd[cp]: user: root - commands: id ${settings.manage_username} &>/dev/null || { echo "User does not exist"; exit 1; } + commands: |- + # Source the logging helper + source /home/jelastic/add-sftp-user-addon/log_helper.sh + + # Log start of password change + jps_log "INFO" "======== STARTING PASSWORD CHANGE ========" "password_change.log" + jps_log "INFO" "Verifying user exists: ${settings.manage_username}" "password_change.log" + + # Check if user exists + if jps_log_cmd "id ${settings.manage_username} &>/dev/null" "Checking if user exists" "password_change.log"; then + jps_log "INFO" "User ${settings.manage_username} exists" "password_change.log" + exit 0 + else + jps_log "ERROR" "User ${settings.manage_username} does not exist" "password_change.log" + echo "User does not exist" + exit 1 + fi - if ("${response.exitStatus}" != "0"): return: type: error message: "User ${settings.manage_username} does not exist." + + # Use custom password if provided, otherwise generate one + - if ('${settings.custom_password}' != ''): + setGlobals: + password: ${settings.custom_password} + - if ('${settings.custom_password}' == ''): + setGlobals: + password: ${fn.password(12)} + + # Update password - cmd[cp]: user: root - commands: - - echo "${settings.manage_username}:${globals.password}" | chpasswd - - echo "Password changed for ${settings.manage_username}" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log + commands: |- + # Source the logging helper + source /home/jelastic/add-sftp-user-addon/log_helper.sh + + # Log password change + jps_log "INFO" "Changing password for user: ${settings.manage_username}" "password_change.log" + + # Update password + if jps_log_cmd "echo \"${settings.manage_username}:${globals.password}\" | chpasswd" "Changing user password" "password_change.log"; then + jps_log "SUCCESS" "Password changed successfully for ${settings.manage_username}" "password_change.log" + else + jps_log "ERROR" "Failed to change password for ${settings.manage_username}" "password_change.log" + exit 1 + fi + + # Log password change to main log + jps_log_cmd "echo \"Password changed for ${settings.manage_username} at $(date)\" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log" "Recording password change in main log" "password_change.log" + + # Log completion + jps_log "SUCCESS" "======== PASSWORD CHANGE COMPLETED ========" "password_change.log" - if ("${response.exitStatus}" != "0"): return: passwordChangeError - return: passwordChangeSuccess delete_user: + # Verify user exists first - cmd[cp]: user: root - commands: - - userdel ${settings.manage_username} - - rm -rf /home/sftpusers/${settings.manage_username} - - echo "User ${settings.manage_username} deleted" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log - + commands: |- + # Source the logging helper + source /home/jelastic/add-sftp-user-addon/log_helper.sh + + # Log start of user deletion + jps_log "INFO" "======== STARTING USER DELETION ========" "user_deletion.log" + jps_log "INFO" "Verifying user exists: ${settings.manage_username}" "user_deletion.log" + + # Check if user exists + if jps_log_cmd "id ${settings.manage_username} &>/dev/null" "Checking if user exists" "user_deletion.log"; then + jps_log "INFO" "User ${settings.manage_username} exists" "user_deletion.log" + else + jps_log "ERROR" "User ${settings.manage_username} does not exist" "user_deletion.log" + echo "User does not exist" + exit 1 + fi + - if ("${response.exitStatus}" != "0"): + return: + type: error + message: "User ${settings.manage_username} does not exist." + + # Check if user is in sftpusers directory + - cmd[cp]: + user: root + commands: |- + # Source the logging helper + source /home/jelastic/add-sftp-user-addon/log_helper.sh + + # Verify home directory exists + jps_log "INFO" "Checking home directory for: ${settings.manage_username}" "user_deletion.log" + + if jps_log_cmd "test -d /home/sftpusers/${settings.manage_username}" "Checking user home directory" "user_deletion.log"; then + jps_log "INFO" "Home directory found: /home/sftpusers/${settings.manage_username}" "user_deletion.log" + else + jps_log "ERROR" "Home directory not found for user: ${settings.manage_username}" "user_deletion.log" + echo "User home directory not found" + exit 1 + fi + - if ("${response.exitStatus}" != "0"): + return: + type: error + message: "User ${settings.manage_username} exists but their home directory was not found." + + # Perform deletion + - cmd[cp]: + user: root + commands: |- + # Source the logging helper + source /home/jelastic/add-sftp-user-addon/log_helper.sh + + # Log deletion process + jps_log "INFO" "Starting deletion of user: ${settings.manage_username}" "user_deletion.log" + + # Delete user account + if jps_log_cmd "userdel ${settings.manage_username}" "Deleting user account" "user_deletion.log"; then + jps_log "SUCCESS" "User account deleted: ${settings.manage_username}" "user_deletion.log" + else + jps_log "ERROR" "Failed to delete user account: ${settings.manage_username}" "user_deletion.log" + exit 1 + fi + + # Remove home directory + if jps_log_cmd "rm -rf /home/sftpusers/${settings.manage_username}" "Removing user home directory" "user_deletion.log"; then + jps_log "SUCCESS" "Home directory removed: /home/sftpusers/${settings.manage_username}" "user_deletion.log" + else + jps_log "WARNING" "Failed to remove home directory for: ${settings.manage_username}" "user_deletion.log" + fi + + # Log to main log file + jps_log_cmd "echo \"User ${settings.manage_username} deleted at $(date)\" >> /home/jelastic/add-sftp-user-addon/logs/script_output.log" "Recording user deletion in main log" "user_deletion.log" + + # Log completion + jps_log "SUCCESS" "======== USER DELETION COMPLETED ========" "user_deletion.log" - if ("${response.exitStatus}" != "0"): return: deleteUserError - - return: deleteUserSuccess + - return: deleteUserSuccess list_users: - cmd[cp]: user: root - commands: ls -ld /home/sftpusers/* | awk '{printf "Username %s - Created %s %s %s\n", substr($9, 17), $6, $7, $8}' + commands: |- + # Source the logging helper + source /home/jelastic/add-sftp-user-addon/log_helper.sh + + # Log list users action + jps_log "INFO" "======== LISTING SFTP USERS ========" "list_users.log" + + # Note: This functionality replaces the retired userlogs.sh script + # with a more efficient and integrated approach + + # Get detailed user information + USER_INFO=$(jps_get_user_info "list_users.log") + + # Output the result + if [ -z "$USER_INFO" ]; then + jps_log "WARNING" "No SFTP users found" "list_users.log" + echo "" + else + jps_log "SUCCESS" "Retrieved list of SFTP users" "list_users.log" + echo "$USER_INFO" + fi + + jps_log "INFO" "======== USER LISTING COMPLETED ========" "list_users.log" + - if ("${response.exitStatus}" != "0" || "${response.out}" == ""): + return: + type: warning + message: "No SFTP users found. Use the Add SFTP/SSH User button to create one." - return: listUsers responses: installSuccess: type: success - message: "Installed Successfully" + message: "Add SFTP User addon installed successfully for Jelastic Virtuozzo LLSMP" sftpError: type: error message: "Failed to add SFTP user. Please check the server logs for more details." diff --git a/scripts/userlogs.sh b/scripts/userlogs.sh deleted file mode 100644 index e1c8c7d..0000000 --- a/scripts/userlogs.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -getent passwd | awk -F: '/^user/ {print $1}' | while read -r user; do - # Attempt to get the user's creation date from the shadow file - creation_date=$(sudo chage -l "$user" | grep 'Last password change' | cut -d: -f2) - echo "$user was created on $creation_date" -done