0
0
Fork 0
mirror of https://github.com/atmoz/sftp.git synced 2024-12-01 13:00:56 -05:00

Merge branch 'master' into alpine

This commit is contained in:
Adrian Dvergsdal 2017-10-08 19:09:53 +02:00
commit f0a6d05edd
4 changed files with 87 additions and 59 deletions

View file

@ -1,6 +1,7 @@
FROM alpine:3.6 FROM alpine:3.6
MAINTAINER Adrian Dvergsdal [atmoz.net] MAINTAINER Adrian Dvergsdal [atmoz.net]
# Steps done in one RUN layer:
# - Install packages # - Install packages
# - Fix default group (1000 does not exist) # - Fix default group (1000 does not exist)
# - OpenSSH needs /var/run/sshd to run # - OpenSSH needs /var/run/sshd to run
@ -13,7 +14,6 @@ RUN echo "@community http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /et
COPY sshd_config /etc/ssh/sshd_config COPY sshd_config /etc/ssh/sshd_config
COPY entrypoint / COPY entrypoint /
COPY README.md /
EXPOSE 22 EXPOSE 22

View file

@ -18,7 +18,7 @@ This is an automated build linked with the [debian](https://hub.docker.com/_/deb
# Usage # Usage
- Required: define users as command arguments, STDIN or mounted in `/etc/sftp/users.conf` - Required: define users in command arguments or in file mounted as `/etc/sftp/users.conf`
(syntax: `user:pass[:e][:uid[:gid[:dir1[,dir2]...]]]...`). (syntax: `user:pass[:e][:uid[:gid[:dir1[,dir2]...]]]...`).
- Set UID/GID manually for your users if you want them to make changes to - Set UID/GID manually for your users if you want them to make changes to
your mounted volumes with permissions matching your host filesystem. your mounted volumes with permissions matching your host filesystem.

View file

@ -1,45 +1,58 @@
#!/bin/bash #!/bin/bash
set -e set -e
export DEBIAN_FRONTEND=noninteractive
# Paths
userConfPath="/etc/sftp/users.conf" userConfPath="/etc/sftp/users.conf"
userConfPathLegacy="/etc/sftp-users.conf" userConfPathLegacy="/etc/sftp-users.conf"
userConfFinalPath="/var/run/sftp/users.conf" userConfFinalPath="/var/run/sftp/users.conf"
function printHelp() { # Extended regular expression (ERE) for arguments
echo "Add users as command arguments, STDIN or mounted in $userConfPath" reUser='[a-z_][a-z0-9._-]{0,31}'
echo "Syntax: user:pass[:e][:uid[:gid[:dir1[,dir2]...]]] ..." rePass='[^:]{0,255}'
echo "Use --readme for more information and examples." reUid='[[:digit:]]*'
reGid='[[:digit:]]*'
reDir='[^:]*'
reArgs="^($reUser)(:$rePass)(:e)?(:$reUid)?(:$reGid)?(:$reDir)?$"
reArgsMaybe="^[^:[:space:]]+:.*$" # Smallest indication of attempt to use argument
reArgSkip='^([[:blank:]]*#.*|[[:blank:]]*)$' # comment or empty line
function log() {
echo "[entrypoint] $@"
} }
function printReadme() { function validateArg() {
cat /README.md name="$1"
echo "TIP: Read this in HTML format here: https://github.com/atmoz/sftp" 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() { function createUser() {
IFS=':' read -a param <<< $@ log "Parsing user data: \"$@\""
user="${param[0]}"
pass="${param[1]}"
if [ "${param[2]}" == "e" ]; then 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" chpasswdOptions="-e"
uid="${param[3]}" index=1
gid="${param[4]}"
dir="${param[5]}"
else
uid="${param[2]}"
gid="${param[3]}"
dir="${param[4]}"
fi fi
if [ -z "$user" ]; then uid="${args[$[$index+2]]}"; validateArg "UID" "$uid" "$reUid" || return 1
echo "FATAL: You must at least provide a username." gid="${args[$[$index+3]]}"; validateArg "GID" "$gid" "$reGid" || return 1
exit 1 dir="${args[$[$index+4]]}"; validateArg "dirs" "$dir" "$reDir" || return 1
fi
if $(cat /etc/passwd | cut -d: -f1 | grep -q "^$user:"); then if $(cat /etc/passwd | cut -d: -f1 | grep -q "^$user:"); then
echo "WARNING: User \"$user\" already exists. Skipping." log "WARNING: User \"$user\" already exists. Skipping."
return 0 return 0
fi fi
@ -79,26 +92,27 @@ function createUser() {
chmod 600 /home/$user/.ssh/authorized_keys chmod 600 /home/$user/.ssh/authorized_keys
fi fi
# Make sure dirs exists and has correct permissions # Make sure dirs exists
if [ -n "$dir" ]; then if [ -n "$dir" ]; then
IFS=',' read -a dirParam <<< $dir IFS=',' read -a dirArgs <<< $dir
for dirPath in ${dirParam[@]}; do for dirPath in ${dirArgs[@]}; do
dirPath=/home/$user/$dirPath dirPath="/home/$user/$dirPath"
echo "Creating and/or setting permissions on $dirPath" if [ ! -d "$dirPath" ]; then
mkdir -p $dirPath log "Creating directory: $dirPath"
chown -R $uid:users $dirPath mkdir -p $dirPath
chown -R $uid:users $dirPath
else
log "Directory already exists: $dirPath"
fi
done done
fi fi
} }
if [[ $1 =~ ^--help$|^-h$ ]]; then # Allow running other programs, e.g. bash
printHelp if [[ -z "$1" || "$1" =~ $reArgsMaybe ]]; then
exit 0 startSshd=true
fi else
startSshd=false
if [ "$1" == "--readme" ]; then
printReadme
exit 0
fi fi
# Backward compatibility with legacy config path # Backward compatibility with legacy config path
@ -113,32 +127,35 @@ if [ ! -f "$userConfFinalPath" ]; then
# Append mounted config to final config # Append mounted config to final config
if [ -f "$userConfPath" ]; then if [ -f "$userConfPath" ]; then
cat "$userConfPath" | grep -v -e '^$' > "$userConfFinalPath" cat "$userConfPath" | grep -v -E "$reArgSkip" > "$userConfFinalPath"
fi fi
# Append users from arguments to final config
for user in "$@"; do
echo "$user" >> "$userConfFinalPath"
done
# Append users from STDIN to final config # 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 if [ ! -t 0 ]; then
while IFS= read -r user || [[ -n "$user" ]]; do while IFS= read -r user || [[ -n "$user" ]]; do
echo "$user" >> "$userConfFinalPath" echo "$user" >> "$userConfFinalPath"
done done
fi fi
# Check that we have users in config if $startSshd; then
if [ "$(cat "$userConfFinalPath" | wc -l)" == 0 ]; then # Append users from arguments to final config
echo "FATAL: No users provided!" for user in "$@"; do
printHelp echo "$user" >> "$userConfFinalPath"
exit 3 done
fi fi
# Import users from final conf file # Check that we have users in config
while IFS= read -r user || [[ -n "$user" ]]; do if [[ -f "$userConfFinalPath" && "$(cat "$userConfFinalPath" | wc -l)" > 0 ]]; then
createUser "$user" # Import users from final conf file
done < "$userConfFinalPath" 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 # Generate unique ssh keys for this container, if needed
if [ ! -f /etc/ssh/ssh_host_ed25519_key ]; then if [ ! -f /etc/ssh/ssh_host_ed25519_key ]; then
@ -153,11 +170,17 @@ fi
if [ -d /etc/sftp.d ]; then if [ -d /etc/sftp.d ]; then
for f in /etc/sftp.d/*; do for f in /etc/sftp.d/*; do
if [ -x "$f" ]; then if [ -x "$f" ]; then
echo "Running $f ..." log "Running $f ..."
$f $f
fi fi
done done
unset f unset f
fi fi
exec /usr/sbin/sshd -D -e if $startSshd; then
log "Executing sshd"
exec /usr/sbin/sshd -D -e
else
log "Executing $@"
exec "$@"
fi

View file

@ -44,6 +44,10 @@ function beforeTest() {
mkdir "$tmpDir" mkdir "$tmpDir"
echo "test::$(id -u):$(id -g):dir1,dir2" >> "$tmpDir/users" echo "test::$(id -u):$(id -g):dir1,dir2" >> "$tmpDir/users"
echo "" >> "$tmpDir/users" # empty line
echo "# comments are allowed" >> "$tmpDir/users"
echo " " >> "$tmpDir/users" # only whitespace
echo " # with whitespace in front" >> "$tmpDir/users"
echo "user.with.dot::$(id -u):$(id -g)" >> "$tmpDir/users" echo "user.with.dot::$(id -u):$(id -g)" >> "$tmpDir/users"
$sudo docker run \ $sudo docker run \
-v "$tmpDir/users:/etc/sftp/users.conf:ro" \ -v "$tmpDir/users:/etc/sftp/users.conf:ro" \
@ -169,6 +173,7 @@ function testDir() {
assertReturn $? 0 assertReturn $? 0
} }
# Smallest user config possible
function testMinimalContainerStart() { function testMinimalContainerStart() {
$skipAllTests && skip && return 0 $skipAllTests && skip && return 0
@ -177,7 +182,7 @@ function testMinimalContainerStart() {
$sudo docker run \ $sudo docker run \
--name "$tmpContainerName" \ --name "$tmpContainerName" \
-d "$sftpImageName" \ -d "$sftpImageName" \
minimal \ m: \
> "$redirect" > "$redirect"
waitForServer $tmpContainerName waitForServer $tmpContainerName