mirror of
https://github.com/atmoz/sftp.git
synced 2024-11-24 12:59:24 -05:00
Validation of args and allow command override
Using regex to validate arguments. Remove readme and usage output from image (expecting people to read documentation online). Some cleanups.
This commit is contained in:
parent
06a7f85d0f
commit
da53454b4b
4 changed files with 70 additions and 51 deletions
|
@ -1,6 +1,7 @@
|
||||||
FROM debian:stretch
|
FROM debian:stretch
|
||||||
MAINTAINER Adrian Dvergsdal [atmoz.net]
|
MAINTAINER Adrian Dvergsdal [atmoz.net]
|
||||||
|
|
||||||
|
# Steps done in one RUN layer:
|
||||||
# - Install packages
|
# - Install packages
|
||||||
# - OpenSSH needs /var/run/sshd to run
|
# - OpenSSH needs /var/run/sshd to run
|
||||||
# - Remove generic host keys, entrypoint generates unique keys
|
# - Remove generic host keys, entrypoint generates unique keys
|
||||||
|
@ -12,7 +13,6 @@ RUN apt-get update && \
|
||||||
|
|
||||||
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.
|
||||||
|
|
114
entrypoint
114
entrypoint
|
@ -1,45 +1,57 @@
|
||||||
#!/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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
@ -91,14 +103,11 @@ function createUser() {
|
||||||
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
|
||||||
|
@ -116,29 +125,32 @@ if [ ! -f "$userConfFinalPath" ]; then
|
||||||
cat "$userConfPath" | grep -v -e '^$' > "$userConfFinalPath"
|
cat "$userConfPath" | grep -v -e '^$' > "$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 +165,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
|
||||||
|
|
|
@ -169,6 +169,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 +178,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