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
|
||||
MAINTAINER Adrian Dvergsdal [atmoz.net]
|
||||
|
||||
# Steps done in one RUN layer:
|
||||
# - Install packages
|
||||
# - Fix default group (1000 does not exist)
|
||||
# - 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 entrypoint /
|
||||
COPY README.md /
|
||||
|
||||
EXPOSE 22
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ This is an automated build linked with the [debian](https://hub.docker.com/_/deb
|
|||
|
||||
# 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]...]]]...`).
|
||||
- Set UID/GID manually for your users if you want them to make changes to
|
||||
your mounted volumes with permissions matching your host filesystem.
|
||||
|
|
135
entrypoint
135
entrypoint
|
@ -1,45 +1,58 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Paths
|
||||
userConfPath="/etc/sftp/users.conf"
|
||||
userConfPathLegacy="/etc/sftp-users.conf"
|
||||
userConfFinalPath="/var/run/sftp/users.conf"
|
||||
|
||||
function printHelp() {
|
||||
echo "Add users as command arguments, STDIN or mounted in $userConfPath"
|
||||
echo "Syntax: user:pass[:e][:uid[:gid[:dir1[,dir2]...]]] ..."
|
||||
echo "Use --readme for more information and examples."
|
||||
# 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
|
||||
reArgSkip='^([[:blank:]]*#.*|[[:blank:]]*)$' # comment or empty line
|
||||
|
||||
function log() {
|
||||
echo "[entrypoint] $@"
|
||||
}
|
||||
|
||||
function printReadme() {
|
||||
cat /README.md
|
||||
echo "TIP: Read this in HTML format here: https://github.com/atmoz/sftp"
|
||||
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() {
|
||||
IFS=':' read -a param <<< $@
|
||||
user="${param[0]}"
|
||||
pass="${param[1]}"
|
||||
log "Parsing user data: \"$@\""
|
||||
|
||||
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"
|
||||
uid="${param[3]}"
|
||||
gid="${param[4]}"
|
||||
dir="${param[5]}"
|
||||
else
|
||||
uid="${param[2]}"
|
||||
gid="${param[3]}"
|
||||
dir="${param[4]}"
|
||||
index=1
|
||||
fi
|
||||
|
||||
if [ -z "$user" ]; then
|
||||
echo "FATAL: You must at least provide a username."
|
||||
exit 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
|
||||
echo "WARNING: User \"$user\" already exists. Skipping."
|
||||
log "WARNING: User \"$user\" already exists. Skipping."
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
@ -79,26 +92,27 @@ function createUser() {
|
|||
chmod 600 /home/$user/.ssh/authorized_keys
|
||||
fi
|
||||
|
||||
# Make sure dirs exists and has correct permissions
|
||||
# Make sure dirs exists
|
||||
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
|
||||
IFS=',' read -a dirArgs <<< $dir
|
||||
for dirPath in ${dirArgs[@]}; do
|
||||
dirPath="/home/$user/$dirPath"
|
||||
if [ ! -d "$dirPath" ]; then
|
||||
log "Creating directory: $dirPath"
|
||||
mkdir -p $dirPath
|
||||
chown -R $uid:users $dirPath
|
||||
else
|
||||
log "Directory already exists: $dirPath"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ $1 =~ ^--help$|^-h$ ]]; then
|
||||
printHelp
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$1" == "--readme" ]; then
|
||||
printReadme
|
||||
exit 0
|
||||
# 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
|
||||
|
@ -113,32 +127,35 @@ if [ ! -f "$userConfFinalPath" ]; then
|
|||
|
||||
# Append mounted config to final config
|
||||
if [ -f "$userConfPath" ]; then
|
||||
cat "$userConfPath" | grep -v -e '^$' > "$userConfFinalPath"
|
||||
cat "$userConfPath" | grep -v -E "$reArgSkip" > "$userConfFinalPath"
|
||||
fi
|
||||
|
||||
# Append users from arguments to final config
|
||||
for user in "$@"; do
|
||||
echo "$user" >> "$userConfFinalPath"
|
||||
done
|
||||
|
||||
# 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
|
||||
|
||||
# Check that we have users in config
|
||||
if [ "$(cat "$userConfFinalPath" | wc -l)" == 0 ]; then
|
||||
echo "FATAL: No users provided!"
|
||||
printHelp
|
||||
exit 3
|
||||
if $startSshd; then
|
||||
# Append users from arguments to final config
|
||||
for user in "$@"; do
|
||||
echo "$user" >> "$userConfFinalPath"
|
||||
done
|
||||
fi
|
||||
|
||||
# Import users from final conf file
|
||||
while IFS= read -r user || [[ -n "$user" ]]; do
|
||||
createUser "$user"
|
||||
done < "$userConfFinalPath"
|
||||
# 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
|
||||
|
@ -153,11 +170,17 @@ fi
|
|||
if [ -d /etc/sftp.d ]; then
|
||||
for f in /etc/sftp.d/*; do
|
||||
if [ -x "$f" ]; then
|
||||
echo "Running $f ..."
|
||||
log "Running $f ..."
|
||||
$f
|
||||
fi
|
||||
done
|
||||
unset f
|
||||
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"
|
||||
|
||||
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"
|
||||
$sudo docker run \
|
||||
-v "$tmpDir/users:/etc/sftp/users.conf:ro" \
|
||||
|
@ -169,6 +173,7 @@ function testDir() {
|
|||
assertReturn $? 0
|
||||
}
|
||||
|
||||
# Smallest user config possible
|
||||
function testMinimalContainerStart() {
|
||||
$skipAllTests && skip && return 0
|
||||
|
||||
|
@ -177,7 +182,7 @@ function testMinimalContainerStart() {
|
|||
$sudo docker run \
|
||||
--name "$tmpContainerName" \
|
||||
-d "$sftpImageName" \
|
||||
minimal \
|
||||
m: \
|
||||
> "$redirect"
|
||||
|
||||
waitForServer $tmpContainerName
|
||||
|
|
Loading…
Reference in a new issue