ngbs 5 years ago
parent
commit
b7e14fdf88
3 changed files with 361 additions and 7 deletions
  1. 1 0
      .gitignore
  2. 65 7
      samba/Dockerfile
  3. 295 0
      samba/samba.sh

+ 1 - 0
.gitignore

@@ -7,6 +7,7 @@
 *.bak
 *.log
 *.md
+!samba.sh
 !builder.sh
 !entrypoint.sh
 !README*.md

+ 65 - 7
samba/Dockerfile

@@ -1,8 +1,66 @@
 FROM playn/alpine:3.12.0
-COPY *.conf /config/
-RUN apk --no-cache add samba samba-common-tools supervisor && \
-    mkdir /shared && \
-    addgroup -g 1000 playn && \
-    adduser -D -H -G playn -s /bin/false -u 1000 playn && \
-    echo -e "12345\n12345" | smbpasswd -a -s -c /config/smb.conf playn
-ENTRYPOINT ["supervisord", "-c", "/config/supervisord.conf"]
+
+RUN apk --no-cache --no-progress upgrade && \
+    apk --no-cache --no-progress add bash samba shadow tini && \
+    addgroup -S smb && \
+    adduser -S -D -H -h /tmp -s /sbin/nologin -G smb -g 'Samba User' smbuser &&\
+    file="/etc/samba/smb.conf" && \
+    sed -i 's|^;* *\(log file = \).*|   \1/dev/stdout|' $file && \
+    sed -i 's|^;* *\(load printers = \).*|   \1no|' $file && \
+    sed -i 's|^;* *\(printcap name = \).*|   \1/dev/null|' $file && \
+    sed -i 's|^;* *\(printing = \).*|   \1bsd|' $file && \
+    sed -i 's|^;* *\(unix password sync = \).*|   \1no|' $file && \
+    sed -i 's|^;* *\(preserve case = \).*|   \1yes|' $file && \
+    sed -i 's|^;* *\(short preserve case = \).*|   \1yes|' $file && \
+    sed -i 's|^;* *\(default case = \).*|   \1lower|' $file && \
+    sed -i '/Share Definitions/,$d' $file && \
+    echo '   pam password change = yes' >>$file && \
+    echo '   map to guest = bad user' >>$file && \
+    echo '   usershare allow guests = yes' >>$file && \
+    echo '   create mask = 0664' >>$file && \
+    echo '   force create mode = 0664' >>$file && \
+    echo '   directory mask = 0775' >>$file && \
+    echo '   force directory mode = 0775' >>$file && \
+    echo '   force user = smbuser' >>$file && \
+    echo '   force group = smb' >>$file && \
+    echo '   follow symlinks = yes' >>$file && \
+    echo '   load printers = no' >>$file && \
+    echo '   printing = bsd' >>$file && \
+    echo '   printcap name = /dev/null' >>$file && \
+    echo '   disable spoolss = yes' >>$file && \
+    echo '   strict locking = no' >>$file && \
+    echo '   aio read size = 0' >>$file && \
+    echo '   aio write size = 0' >>$file && \
+    echo '   vfs objects = catia fruit recycle streams_xattr' >>$file && \
+    echo '   recycle:keeptree = yes' >>$file && \
+    echo '   recycle:maxsize = 0' >>$file && \
+    echo '   recycle:repository = .deleted' >>$file && \
+    echo '   recycle:versions = yes' >>$file && \
+    echo '' >>$file && \
+    echo '   # Security' >>$file && \
+    echo '   client ipc max protocol = SMB3' >>$file && \
+    echo '   client ipc min protocol = SMB2_10' >>$file && \
+    echo '   client max protocol = SMB3' >>$file && \
+    echo '   client min protocol = SMB2_10' >>$file && \
+    echo '   server max protocol = SMB3' >>$file && \
+    echo '   server min protocol = SMB2_10' >>$file && \
+    echo '' >>$file && \
+    echo '   # Time Machine' >>$file && \
+    echo '   fruit:delete_empty_adfiles = yes' >>$file && \
+    echo '   fruit:time machine = yes' >>$file && \
+    echo '   fruit:veto_appledouble = no' >>$file && \
+    echo '   fruit:wipe_intentionally_left_blank_rfork = yes' >>$file && \
+    echo '' >>$file && \
+    rm -rf /tmp/*
+
+COPY samba.sh /usr/bin/
+
+EXPOSE 137/udp 138/udp 139 445
+
+HEALTHCHECK --interval=60s --timeout=15s \
+            CMD smbclient -L \\localhost -U % -m SMB3
+
+VOLUME ["/etc", "/var/cache/samba", "/var/lib/samba", "/var/log/samba",\
+            "/run/samba"]
+
+ENTRYPOINT ["/sbin/tini", "--", "/usr/bin/samba.sh"]

+ 295 - 0
samba/samba.sh

@@ -0,0 +1,295 @@
+#!/usr/bin/env bash
+#===============================================================================
+#          FILE: samba.sh
+#
+#         USAGE: ./samba.sh
+#
+#   DESCRIPTION: Entrypoint for samba docker container
+#
+#       OPTIONS: ---
+#  REQUIREMENTS: ---
+#          BUGS: ---
+#         NOTES: ---
+#        AUTHOR: David Personette ([email protected]),
+#  ORGANIZATION:
+#       CREATED: 09/28/2014 12:11
+#      REVISION: 1.0
+#===============================================================================
+
+set -o nounset                              # Treat unset variables as an error
+
+### charmap: setup character mapping for file/directory names
+# Arguments:
+#   chars) from:to character mappings separated by ','
+# Return: configured character mapings
+charmap() { local chars="$1" file=/etc/samba/smb.conf
+    grep -q catia $file || sed -i '/TCP_NODELAY/a \
+\
+    vfs objects = catia\
+    catia:mappings =\
+                ' $file
+
+    sed -i '/catia:mappings/s| =.*| = '"$chars"'|' $file
+}
+
+### generic: set a generic config option in a section
+# Arguments:
+#   section) section of config file
+#   option) raw option
+# Return: line added to smb.conf (replaces existing line with same key)
+generic() { local section="$1" key="$(sed 's| *=.*||' <<< $2)" \
+            value="$(sed 's|[^=]*= *||' <<< $2)" file=/etc/samba/smb.conf
+    if sed -n '/^\['"$section"'\]/,/^\[/p' $file | grep -qE '^;*\s*'"$key"; then
+        sed -i '/^\['"$1"'\]/,/^\[/s|^;*\s*\('"$key"' = \).*|   \1'"$value"'|' \
+                    "$file"
+    else
+        sed -i '/\['"$section"'\]/a \   '"$key = $value" "$file"
+    fi
+}
+
+### global: set a global config option
+# Arguments:
+#   option) raw option
+# Return: line added to smb.conf (replaces existing line with same key)
+global() { local key="$(sed 's| *=.*||' <<< $1)" \
+            value="$(sed 's|[^=]*= *||' <<< $1)" file=/etc/samba/smb.conf
+    if sed -n '/^\[global\]/,/^\[/p' $file | grep -qE '^;*\s*'"$key"; then
+        sed -i '/^\[global\]/,/^\[/s|^;*\s*\('"$key"' = \).*|   \1'"$value"'|' \
+                    "$file"
+    else
+        sed -i '/\[global\]/a \   '"$key = $value" "$file"
+    fi
+}
+
+### include: add a samba config file include
+# Arguments:
+#   file) file to import
+include() { local includefile="$1" file=/etc/samba/smb.conf
+    sed -i "\\|include = $includefile|d" "$file"
+    echo "include = $includefile" >> "$file"
+}
+
+### import: import a smbpasswd file
+# Arguments:
+#   file) file to import
+# Return: user(s) added to container
+import() { local file="$1" name id
+    while read name id; do
+        grep -q "^$name:" /etc/passwd || adduser -D -H -u "$id" "$name"
+    done < <(cut -d: -f1,2 $file | sed 's/:/ /')
+    pdbedit -i smbpasswd:$file
+}
+
+### perms: fix ownership and permissions of share paths
+# Arguments:
+#   none)
+# Return: result
+perms() { local i file=/etc/samba/smb.conf
+    for i in $(awk -F ' = ' '/   path = / {print $2}' $file); do
+        chown -Rh smbuser. $i
+        find $i -type d ! -perm 775 -exec chmod 775 {} \;
+        find $i -type f ! -perm 0664 -exec chmod 0664 {} \;
+    done
+}
+export -f perms
+
+### recycle: disable recycle bin
+# Arguments:
+#   none)
+# Return: result
+recycle() { local file=/etc/samba/smb.conf
+    sed -i '/recycle:/d; /vfs objects/s/ recycle / /' $file
+}
+
+### share: Add share
+# Arguments:
+#   share) share name
+#   path) path to share
+#   browsable) 'yes' or 'no'
+#   readonly) 'yes' or 'no'
+#   guest) 'yes' or 'no'
+#   users) list of allowed users
+#   admins) list of admin users
+#   writelist) list of users that can write to a RO share
+#   comment) description of share
+# Return: result
+share() { local share="$1" path="$2" browsable="${3:-yes}" ro="${4:-yes}" \
+                guest="${5:-yes}" users="${6:-""}" admins="${7:-""}" \
+                writelist="${8:-""}" comment="${9:-""}" file=/etc/samba/smb.conf
+    sed -i "/\\[$share\\]/,/^\$/d" $file
+    echo "[$share]" >>$file
+    echo "   path = $path" >>$file
+    echo "   browsable = $browsable" >>$file
+    echo "   read only = $ro" >>$file
+    echo "   guest ok = $guest" >>$file
+    [[ ${VETO:-yes} == no ]] || {
+        echo -n "   veto files = /.apdisk/.DS_Store/.TemporaryItems/" >>$file
+        echo -n ".Trashes/desktop.ini/ehthumbs.db/Network Trash Folder/" >>$file
+        echo "Temporary Items/Thumbs.db/" >>$file
+        echo "   delete veto files = yes" >>$file
+    }
+    [[ ${users:-""} && ! ${users:-""} == all ]] &&
+        echo "   valid users = $(tr ',' ' ' <<< $users)" >>$file
+    [[ ${admins:-""} && ! ${admins:-""} =~ none ]] &&
+        echo "   admin users = $(tr ',' ' ' <<< $admins)" >>$file
+    [[ ${writelist:-""} && ! ${writelist:-""} =~ none ]] &&
+        echo "   write list = $(tr ',' ' ' <<< $writelist)" >>$file
+    [[ ${comment:-""} && ! ${comment:-""} =~ none ]] &&
+        echo "   comment = $(tr ',' ' ' <<< $comment)" >>$file
+    echo "" >>$file
+    [[ -d $path ]] || mkdir -p $path
+}
+
+### smb: disable SMB2 minimum
+# Arguments:
+#   none)
+# Return: result
+smb() { local file=/etc/samba/smb.conf
+    sed -i 's/\([^#]*min protocol *=\).*/\1 LANMAN1/' $file
+}
+
+### user: add a user
+# Arguments:
+#   name) for user
+#   password) for user
+#   id) for user
+#   group) for user
+#   gid) for group
+# Return: user added to container
+user() { local name="$1" passwd="$2" id="${3:-""}" group="${4:-""}" \
+                gid="${5:-""}"
+    [[ "$group" ]] && { grep -q "^$group:" /etc/group ||
+                addgroup ${gid:+--gid $gid }"$group"; }
+    grep -q "^$name:" /etc/passwd ||
+        adduser -D -H ${group:+-G $group} ${id:+-u $id} "$name"
+    echo -e "$passwd\n$passwd" | smbpasswd -s -a "$name"
+}
+
+### workgroup: set the workgroup
+# Arguments:
+#   workgroup) the name to set
+# Return: configure the correct workgroup
+workgroup() { local workgroup="$1" file=/etc/samba/smb.conf
+    sed -i 's|^\( *workgroup = \).*|\1'"$workgroup"'|' $file
+}
+
+### widelinks: allow access wide symbolic links
+# Arguments:
+#   none)
+# Return: result
+widelinks() { local file=/etc/samba/smb.conf \
+            replace='\1\n   wide links = yes\n   unix extensions = no'
+    sed -i 's/\(follow symlinks = yes\)/'"$replace"'/' $file
+}
+
+### usage: Help
+# Arguments:
+#   none)
+# Return: Help text
+usage() { local RC="${1:-0}"
+    echo "Usage: ${0##*/} [-opt] [command]
+Options (fields in '[]' are optional, '<>' are required):
+    -h          This help
+    -c \"<from:to>\" setup character mapping for file/directory names
+                required arg: \"<from:to>\" character mappings separated by ','
+    -G \"<section;parameter>\" Provide generic section option for smb.conf
+                required arg: \"<section>\" - IE: \"share\"
+                required arg: \"<parameter>\" - IE: \"log level = 2\"
+    -g \"<parameter>\" Provide global option for smb.conf
+                required arg: \"<parameter>\" - IE: \"log level = 2\"
+    -i \"<path>\" Import smbpassword
+                required arg: \"<path>\" - full file path in container
+    -n          Start the 'nmbd' daemon to advertise the shares
+    -p          Set ownership and permissions on the shares
+    -r          Disable recycle bin for shares
+    -S          Disable SMB2 minimum version
+    -s \"<name;/path>[;browse;readonly;guest;users;admins;writelist;comment]\"
+                Configure a share
+                required arg: \"<name>;</path>\"
+                <name> is how it's called for clients
+                <path> path to share
+                NOTE: for the default value, just leave blank
+                [browsable] default:'yes' or 'no'
+                [readonly] default:'yes' or 'no'
+                [guest] allowed default:'yes' or 'no'
+                NOTE: for user lists below, usernames are separated by ','
+                [users] allowed default:'all' or list of allowed users
+                [admins] allowed default:'none' or list of admin users
+                [writelist] list of users that can write to a RO share
+                [comment] description of share
+    -u \"<username;password>[;ID;group;GID]\"       Add a user
+                required arg: \"<username>;<passwd>\"
+                <username> for user
+                <password> for user
+                [ID] for user
+                [group] for user
+                [GID] for group
+    -w \"<workgroup>\"       Configure the workgroup (domain) samba should use
+                required arg: \"<workgroup>\"
+                <workgroup> for samba
+    -W          Allow access wide symbolic links
+    -I          Add an include option at the end of the smb.conf
+                required arg: \"<include file path>\"
+                <include file path> in the container, e.g. a bind mount
+The 'command' (if provided and valid) will be run instead of samba
+" >&2
+    exit $RC
+}
+
+[[ "${USERID:-""}" =~ ^[0-9]+$ ]] && usermod -u $USERID -o smbuser
+[[ "${GROUPID:-""}" =~ ^[0-9]+$ ]] && groupmod -g $GROUPID -o smb
+
+while getopts ":hc:G:g:i:nprs:Su:Ww:I:" opt; do
+    case "$opt" in
+        h) usage ;;
+        c) charmap "$OPTARG" ;;
+        G) eval generic $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $OPTARG) ;;
+        g) global "$OPTARG" ;;
+        i) import "$OPTARG" ;;
+        n) NMBD="true" ;;
+        p) PERMISSIONS="true" ;;
+        r) recycle ;;
+        s) eval share $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $OPTARG) ;;
+        S) smb ;;
+        u) eval user $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $OPTARG) ;;
+        w) workgroup "$OPTARG" ;;
+        W) widelinks ;;
+        I) include "$OPTARG" ;;
+        "?") echo "Unknown option: -$OPTARG"; usage 1 ;;
+        ":") echo "No argument value for option: -$OPTARG"; usage 2 ;;
+    esac
+done
+shift $(( OPTIND - 1 ))
+
+[[ "${CHARMAP:-""}" ]] && charmap "$CHARMAP"
+while read i; do
+    eval generic $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $i)
+done < <(env | awk '/^GENERIC[0-9=_]/ {sub (/^[^=]*=/, "", $0); print}')
+while read i; do
+    global "$i"
+done < <(env | awk '/^GLOBAL[0-9=_]/ {sub (/^[^=]*=/, "", $0); print}')
+[[ "${IMPORT:-""}" ]] && import "$IMPORT"
+[[ "${RECYCLE:-""}" ]] && recycle
+while read i; do
+    eval share $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $i)
+done < <(env | awk '/^SHARE[0-9=_]/ {sub (/^[^=]*=/, "", $0); print}')
+[[ "${SMB:-""}" ]] && smb
+while read i; do
+    eval user $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $i)
+done < <(env | awk '/^USER[0-9=_]/ {sub (/^[^=]*=/, "", $0); print}')
+[[ "${WORKGROUP:-""}" ]] && workgroup "$WORKGROUP"
+[[ "${WIDELINKS:-""}" ]] && widelinks
+[[ "${INCLUDE:-""}" ]] && include "$INCLUDE"
+[[ "${PERMISSIONS:-""}" ]] && perms &
+
+if [[ $# -ge 1 && -x $(which $1 2>&-) ]]; then
+    exec "$@"
+elif [[ $# -ge 1 ]]; then
+    echo "ERROR: command not found: $1"
+    exit 13
+elif ps -ef | egrep -v grep | grep -q smbd; then
+    echo "Service already running, please restart container to apply changes"
+else
+    [[ ${NMBD:-""} ]] && ionice -c 3 nmbd -D
+    exec ionice -c 3 smbd -FS --no-process-group </dev/null
+fi