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:
commit
f0a6d05edd
4 changed files with 87 additions and 59 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
135
entrypoint
135
entrypoint
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue