mirror of
https://github.com/atmoz/sftp.git
synced 2024-11-17 12:51:33 -05:00
da53454b4b
Using regex to validate arguments. Remove readme and usage output from image (expecting people to read documentation online). Some cleanups.
181 lines
4.9 KiB
Bash
Executable file
181 lines
4.9 KiB
Bash
Executable file
#!/bin/bash
|
|
set -e
|
|
|
|
# Paths
|
|
userConfPath="/etc/sftp/users.conf"
|
|
userConfPathLegacy="/etc/sftp-users.conf"
|
|
userConfFinalPath="/var/run/sftp/users.conf"
|
|
|
|
# Extended regular expression (ERE) for arguments
|
|
reUser='[a-z_][a-z0-9._-]{0,31}'
|
|
rePass='[^:]{0,255}'
|
|
reUid='[[:digit:]]*'
|
|
reGid='[[:digit:]]*'
|
|
reDir='[^:]*'
|
|
reArgs="^($reUser)(:$rePass)(:e)?(:$reUid)?(:$reGid)?(:$reDir)?$"
|
|
reArgsMaybe="^[^:[:space:]]+:.*$" # Smallest indication of attempt to use argument
|
|
|
|
function log() {
|
|
echo "[entrypoint] $@"
|
|
}
|
|
|
|
function validateArg() {
|
|
name="$1"
|
|
val="$2"
|
|
re="$3"
|
|
|
|
if [[ "$val" =~ ^$re$ ]]; then
|
|
return 0
|
|
else
|
|
log "ERROR: Invalid $name \"$val\", do not match required regex pattern: $re"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
function createUser() {
|
|
log "Parsing user data: \"$@\""
|
|
|
|
IFS=':' read -a args <<< $@
|
|
index=0
|
|
|
|
user="${args[0]}"; validateArg "username" "$user" "$reUser" || return 1
|
|
pass="${args[1]}"; validateArg "password" "$pass" "$rePass" || return 1
|
|
|
|
if [ "${args[2]}" == "e" ]; then
|
|
chpasswdOptions="-e"
|
|
index=1
|
|
fi
|
|
|
|
uid="${args[$[$index+2]]}"; validateArg "UID" "$uid" "$reUid" || return 1
|
|
gid="${args[$[$index+3]]}"; validateArg "GID" "$gid" "$reGid" || return 1
|
|
dir="${args[$[$index+4]]}"; validateArg "dirs" "$dir" "$reDir" || return 1
|
|
|
|
if $(cat /etc/passwd | cut -d: -f1 | grep -q "^$user:"); then
|
|
log "WARNING: User \"$user\" already exists. Skipping."
|
|
return 0
|
|
fi
|
|
|
|
useraddOptions="--no-user-group"
|
|
|
|
if [ -n "$uid" ]; then
|
|
useraddOptions="$useraddOptions --non-unique --uid $uid"
|
|
fi
|
|
|
|
if [ -n "$gid" ]; then
|
|
if ! $(cat /etc/group | cut -d: -f3 | grep -q "$gid"); then
|
|
groupadd --gid $gid "group_$gid"
|
|
fi
|
|
|
|
useraddOptions="$useraddOptions --gid $gid"
|
|
fi
|
|
|
|
useradd $useraddOptions $user
|
|
mkdir -p /home/$user
|
|
chown root:root /home/$user
|
|
chmod 755 /home/$user
|
|
|
|
# Retrieving user id to use it in chown commands instead of the user name
|
|
# to avoid problems on alpine when the user name contains a '.'
|
|
uid=`id $user -u`
|
|
|
|
if [ -n "$pass" ]; then
|
|
echo "$user:$pass" | chpasswd $chpasswdOptions
|
|
else
|
|
usermod -p "*" $user # disabled password
|
|
fi
|
|
|
|
# Add SSH keys to authorized_keys with valid permissions
|
|
if [ -d /home/$user/.ssh/keys ]; then
|
|
cat /home/$user/.ssh/keys/* >> /home/$user/.ssh/authorized_keys
|
|
chown $uid /home/$user/.ssh/authorized_keys
|
|
chmod 600 /home/$user/.ssh/authorized_keys
|
|
fi
|
|
|
|
# Make sure dirs exists and has correct permissions
|
|
if [ -n "$dir" ]; then
|
|
IFS=',' read -a dirParam <<< $dir
|
|
for dirPath in ${dirParam[@]}; do
|
|
dirPath=/home/$user/$dirPath
|
|
echo "Creating and/or setting permissions on $dirPath"
|
|
mkdir -p $dirPath
|
|
chown -R $uid:users $dirPath
|
|
done
|
|
fi
|
|
}
|
|
|
|
# Allow running other programs, e.g. bash
|
|
if [[ -z "$1" || "$1" =~ $reArgsMaybe ]]; then
|
|
startSshd=true
|
|
else
|
|
startSshd=false
|
|
fi
|
|
|
|
# Backward compatibility with legacy config path
|
|
if [ ! -f "$userConfPath" -a -f "$userConfPathLegacy" ]; then
|
|
mkdir -p "$(dirname $userConfPath)"
|
|
ln -s "$userConfPathLegacy" "$userConfPath"
|
|
fi
|
|
|
|
# Create users only on first run
|
|
if [ ! -f "$userConfFinalPath" ]; then
|
|
mkdir -p "$(dirname $userConfFinalPath)"
|
|
|
|
# Append mounted config to final config
|
|
if [ -f "$userConfPath" ]; then
|
|
cat "$userConfPath" | grep -v -e '^$' > "$userConfFinalPath"
|
|
fi
|
|
|
|
# Append users from STDIN to final config
|
|
# DEPRECATED on 2017-10-08, DO NOT USE
|
|
# TODO: Remove code after 6-12 months
|
|
if [ ! -t 0 ]; then
|
|
while IFS= read -r user || [[ -n "$user" ]]; do
|
|
echo "$user" >> "$userConfFinalPath"
|
|
done
|
|
fi
|
|
|
|
if $startSshd; then
|
|
# Append users from arguments to final config
|
|
for user in "$@"; do
|
|
echo "$user" >> "$userConfFinalPath"
|
|
done
|
|
fi
|
|
|
|
# Check that we have users in config
|
|
if [[ -f "$userConfFinalPath" && "$(cat "$userConfFinalPath" | wc -l)" > 0 ]]; then
|
|
# Import users from final conf file
|
|
while IFS= read -r user || [[ -n "$user" ]]; do
|
|
createUser "$user"
|
|
done < "$userConfFinalPath"
|
|
elif $startSshd; then
|
|
log "FATAL: No users provided!"
|
|
exit 3
|
|
fi
|
|
|
|
# Generate unique ssh keys for this container, if needed
|
|
if [ ! -f /etc/ssh/ssh_host_ed25519_key ]; then
|
|
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ''
|
|
fi
|
|
if [ ! -f /etc/ssh/ssh_host_rsa_key ]; then
|
|
ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N ''
|
|
fi
|
|
fi
|
|
|
|
# Source custom scripts, if any
|
|
if [ -d /etc/sftp.d ]; then
|
|
for f in /etc/sftp.d/*; do
|
|
if [ -x "$f" ]; then
|
|
log "Running $f ..."
|
|
$f
|
|
fi
|
|
done
|
|
unset f
|
|
fi
|
|
|
|
if $startSshd; then
|
|
log "Executing sshd"
|
|
exec /usr/sbin/sshd -D -e
|
|
else
|
|
log "Executing $@"
|
|
exec "$@"
|
|
fi
|