278 lines
10 KiB
Bash
278 lines
10 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="/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"
|
|
# Set password directly - chpasswd reads username:password from stdin
|
|
# Use printf to handle special characters in password securely
|
|
CHPASSWD_OUTPUT=$(printf '%s:%s\n' "$USERNAME" "$PASSWORD" | chpasswd 2>&1)
|
|
CHPASSWD_STATUS=$?
|
|
if [ -n "$CHPASSWD_OUTPUT" ]; then
|
|
log_debug "chpasswd output: $CHPASSWD_OUTPUT"
|
|
fi
|
|
if [ $CHPASSWD_STATUS -eq 0 ]; then
|
|
log_success "Password set for user $USERNAME"
|
|
else
|
|
log_error "Failed to set password for user $USERNAME"
|
|
echo "ERROR: Failed to set password for user $USERNAME" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# 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"
|
|
|
|
# No additional mounts needed for SSH users (no chroot)
|
|
|
|
# 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"
|
|
|
|
# Ensure webroot has correct group ownership and permissions for write access
|
|
log "Phase 10b: Verifying webroot permissions for group write access"
|
|
if [ -d "$ROOT_DIRECTORY" ]; then
|
|
# Check if litespeed group exists
|
|
if getent group litespeed > /dev/null; then
|
|
# Check current group ownership
|
|
CURRENT_GROUP=$(stat -c '%G' "$ROOT_DIRECTORY" 2>/dev/null)
|
|
if [ "$CURRENT_GROUP" != "litespeed" ]; then
|
|
log "Setting webroot group ownership to litespeed (was: $CURRENT_GROUP)"
|
|
log_cmd "chgrp -R litespeed $ROOT_DIRECTORY" "Setting webroot group to litespeed"
|
|
fi
|
|
|
|
# Check if group write permission exists
|
|
# Group write exists if second digit is 7(rwx), 6(rw-), 3(-wx), or 2(-w-)
|
|
CURRENT_PERMS=$(stat -c '%a' "$ROOT_DIRECTORY" 2>/dev/null)
|
|
if [ -n "$CURRENT_PERMS" ]; then
|
|
# Extract group write bit (second digit)
|
|
GROUP_WRITE_BIT=$(echo "$CURRENT_PERMS" | cut -c2)
|
|
# Check if write bit is NOT set (4=r--, 5=r-x, 1=--x, 0=---)
|
|
if [ "$GROUP_WRITE_BIT" = "4" ] || [ "$GROUP_WRITE_BIT" = "5" ] || [ "$GROUP_WRITE_BIT" = "1" ] || [ "$GROUP_WRITE_BIT" = "0" ]; then
|
|
log "Adding group write permissions to webroot (current: $CURRENT_PERMS)"
|
|
log_cmd "chmod -R g+w $ROOT_DIRECTORY" "Adding group write permissions to webroot"
|
|
else
|
|
log_debug "Webroot already has group write permissions (current: $CURRENT_PERMS)"
|
|
fi
|
|
fi
|
|
else
|
|
log_warning "litespeed group does not exist, skipping webroot permission setup"
|
|
fi
|
|
else
|
|
log_warning "Webroot directory $ROOT_DIRECTORY does not exist, skipping permission check"
|
|
fi
|
|
|
|
# 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 |