add-sftp-user/add-sftp.sh

260 lines
9.6 KiB
Bash

#!/bin/bash
# Set debug mode based on the 4th script argument.
# This must be set BEFORE sourcing the logging library.
export DEBUG=${4:-0}
# Source the canonical logging library.
# The path is relative to this script's location.
source "$(dirname "$0")/scripts/logging.sh"
# Source the canonical system preparation library.
source "$(dirname "$0")/scripts/system_prep.sh"
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
}
# Main script
USERNAME=$1
PASSWORD=$2
SSH_ENABLED=${3:-false}
# Validate required parameters
if [ -z "$USERNAME" ] || [ -z "$PASSWORD" ]; then
echo "ERROR: Missing required parameters. Usage: $0 <username> <password> [ssh_enabled]" >&2
exit 1
fi
# Log to file only
log "======== STARTING SFTP USER SETUP ========"
log "Script started with username: $USERNAME, ssh_enabled: $SSH_ENABLED"
# Pre-flight checks
log "Phase 0: Pre-flight environment checks"
if [ ! -d "/var/www/webroot/ROOT" ]; then
log_error "Web root directory /var/www/webroot/ROOT does not exist"
echo "ERROR: Web root directory /var/www/webroot/ROOT does not exist" >&2
exit 1
fi
if [ ! -x "/usr/sbin/useradd" ]; then
log_error "useradd command not found or not executable"
echo "ERROR: useradd command not found or not executable" >&2
exit 1
fi
if [ ! -x "/usr/sbin/chpasswd" ]; then
log_error "chpasswd command not found or not executable"
echo "ERROR: chpasswd command not found or not executable" >&2
exit 1
fi
log_success "Pre-flight checks passed"
# Log system information
log_system_info
log_debug "Script Parameters: username=$USERNAME, ssh_enabled=$SSH_ENABLED"
# Fix SFTP configuration
log "Phase 1: Configuring SSH/SFTP service"
if ! prepare_sftp_system; then
log_error "Failed to configure SSH/SFTP service, exiting"
echo "ERROR: Failed to configure SSH/SFTP service" >&2
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"
echo "ERROR: Username validation failed for: $USERNAME" >&2
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."
echo "ERROR: Username $USERNAME already exists" >&2
exit 1
fi
log_success "Username is available for creation"
USER_HOME="/home/sftpusers/$USERNAME"
ROOT_DIRECTORY="/var/www/webroot/ROOT"
log_debug "Setting paths - USER_HOME: $USER_HOME, ROOT_DIRECTORY: $ROOT_DIRECTORY"
# 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-only access"
log_cmd "groupadd sftpusers" "Creating sftpusers group"
fi
# Create the sshusers group if it doesn't exist
if ! getent group sshusers > /dev/null; then
log "Creating sshusers group for SFTP+SSH access"
log_cmd "groupadd sshusers" "Creating sshusers 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
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"
# Determine shell path
if [ "$SSH_ENABLED" = "true" ]; then
USER_SHELL="/shell/bin/bash"
else
USER_SHELL="/sbin/nologin"
fi
# Create the user account
log "Phase 6: Creating user account"
if [ "$SSH_ENABLED" = "true" ]; then
log "Creating user with SSH access"
if ! log_cmd "useradd -d $USER_HOME -m -s $USER_SHELL $USERNAME" "Creating user with SSH shell inside jail"; then
log_error "Failed to create user account with SSH access"
echo "ERROR: Failed to create user account with SSH access" >&2
exit 1
fi
else
log "Creating user with SFTP-only access"
if ! log_cmd "useradd -d $USER_HOME -m -s $USER_SHELL $USERNAME" "Creating user with nologin shell"; then
log_error "Failed to create user account with SFTP-only access"
echo "ERROR: Failed to create user account with SFTP-only access" >&2
exit 1
fi
fi
log_success "User account created"
# Set password
log "Phase 7: Setting user password"
if ! log_cmd "echo '$USERNAME:$PASSWORD' | chpasswd" "Setting user password"; then
log_error "Failed to set password for user $USERNAME"
echo "ERROR: Failed to set password for user $USERNAME" >&2
exit 1
fi
log_success "Password set for user $USERNAME"
# 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"
# 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"
# Create mount point for webroot (using bind mount instead of symlink)
log "Phase 9: Setting up webroot access via bind mount"
if ! log_cmd "mkdir -p $USER_HOME/data/ROOT" "Creating ROOT mount point"; then
log_error "Failed to create ROOT mount point directory"
echo "ERROR: Failed to create ROOT mount point directory" >&2
exit 1
fi
# Check if ROOT_DIRECTORY exists before mounting
if [ ! -d "$ROOT_DIRECTORY" ]; then
log_error "Root directory $ROOT_DIRECTORY does not exist"
echo "ERROR: Root directory $ROOT_DIRECTORY does not exist" >&2
exit 1
fi
if ! log_cmd "mount --bind $ROOT_DIRECTORY $USER_HOME/data/ROOT" "Binding webroot to user's ROOT directory"; then
log_error "Failed to create bind mount for webroot access"
echo "ERROR: Failed to create bind mount for webroot access" >&2
exit 1
fi
# Add mount to fstab to persist across reboots
if ! grep -q "$ROOT_DIRECTORY $USER_HOME/data/ROOT" /etc/fstab; then
if ! log_cmd "echo \"$ROOT_DIRECTORY $USER_HOME/data/ROOT none bind 0 0\" >> /etc/fstab" "Adding bind mount to fstab"; then
log_warning "Failed to add bind mount to fstab - mount may not persist across reboots"
fi
fi
log_success "Created bind mount for webroot access"
# Bind shell, dev, and proc into chroot for SSH users
if [ "$SSH_ENABLED" = "true" ]; then
log "Phase 9.1: Mounting shell/dev/proc into chroot"
# 1. shell template
if ! mount | grep -q "${USER_HOME}/shell"; then
log_cmd "mkdir -p ${USER_HOME}/shell" "Creating shell mount point"
log_cmd "mount --bind /home/sftp-shell ${USER_HOME}/shell" "Binding shell template"
grep -q "/home/sftp-shell ${USER_HOME}/shell" /etc/fstab || echo "/home/sftp-shell ${USER_HOME}/shell none bind 0 0" >> /etc/fstab
fi
# 2. dev nodes
if ! mount | grep -q "${USER_HOME}/dev"; then
log_cmd "mkdir -p ${USER_HOME}/dev" "Creating dev mount point"
log_cmd "mount --bind /home/sftp-shell/dev ${USER_HOME}/dev" "Binding dev nodes"
grep -q "/home/sftp-shell/dev ${USER_HOME}/dev" /etc/fstab || echo "/home/sftp-shell/dev ${USER_HOME}/dev none bind 0 0" >> /etc/fstab
fi
# 3. read-only proc
if ! mount | grep -q "${USER_HOME}/proc"; then
log_cmd "mkdir -p ${USER_HOME}/proc" "Creating proc mount point"
log_cmd "mount --bind /proc ${USER_HOME}/proc" "Binding proc"
log_cmd "mount -o remount,bind,ro ${USER_HOME}/proc" "Remount proc read-only"
grep -q "/proc ${USER_HOME}/proc" /etc/fstab || echo "/proc ${USER_HOME}/proc none bind,ro 0 0" >> /etc/fstab
fi
log_success "Shell, dev, and proc mounted into chroot"
fi
# Add user to the required groups
log "Phase 10: Adding user to groups"
if [ "$SSH_ENABLED" = "true" ]; then
log_cmd "usermod -aG sshusers $USERNAME" "Adding user to sshusers group for SSH+SFTP access"
log_success "Added $USERNAME to sshusers group"
else
log_cmd "usermod -aG sftpusers $USERNAME" "Adding user to sftpusers group for SFTP-only access"
log_success "Added $USERNAME to sftpusers group"
fi
log_cmd "usermod -aG litespeed $USERNAME" "Adding user to litespeed group for file access"
log_success "Added $USERNAME to litespeed group for file access"
# Create welcome file
log "Phase 11: Creating welcome file"
cat > $USER_HOME/data/welcome.txt << EOF
Welcome to your SFTP account on Jelastic!
Your account has been set up with the following details:
Username: $USERNAME
Home Directory: $USER_HOME
Web Root: $USER_HOME/data/ROOT (symlink to $ROOT_DIRECTORY)
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"
# Always export variables directly with no console output
export CREATED_USERNAME="$USERNAME"
export CREATED_PASSWORD="$PASSWORD"
# All logging should be to file only
log_success "Script completed successfully for user $USERNAME"
log "======== SFTP USER SETUP COMPLETE ========"
exit 0