diff --git a/.apps.yml b/.apps.yml index 79a6998c8..a53e56045 100644 --- a/.apps.yml +++ b/.apps.yml @@ -50,6 +50,10 @@ apps: repository: home-assistant/app-rpc-shutdown target: rpc_shutdown image: ghcr.io/home-assistant/app-rpc-shutdown + samba: + repository: home-assistant/app-samba + target: samba + image: ghcr.io/home-assistant/app-samba silabs_flasher: repository: home-assistant/app-silabs-flasher target: silabs_flasher diff --git a/.yamllint b/.yamllint index 9e0a9db0c..203b6f10f 100644 --- a/.yamllint +++ b/.yamllint @@ -15,6 +15,7 @@ ignore: | /openthread_border_router/config.yaml /openwakeword/config.yaml /rpc_shutdown/config.yaml + /samba/config.yaml /silabs_flasher/config.yaml /ssh/config.yaml /vlc/config.yaml diff --git a/samba/Dockerfile b/samba/Dockerfile deleted file mode 100644 index c7cd5390d..000000000 --- a/samba/Dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -ARG BUILD_FROM -FROM $BUILD_FROM - -# Add env -ENV LANG C.UTF-8 - -# Setup base -RUN \ - apk add --no-cache samba wsdd \ - && mkdir -p /var/lib/samba \ - && touch \ - /etc/samba/lmhosts \ - /var/lib/samba/account_policy.tdb \ - /var/lib/samba/registry.tdb \ - /var/lib/samba/winbindd_idmap.tdb - -# Copy data -COPY rootfs / - -HEALTHCHECK --start-period=3s \ - CMD smbclient -L '\\localhost' -U '%' -m SMB3 - -ENV \ - S6_STAGE2_HOOK=/etc/s6-overlay/scripts/enable-check.sh diff --git a/samba/build.yaml b/samba/build.yaml deleted file mode 100644 index c9284064c..000000000 --- a/samba/build.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -build_from: - aarch64: ghcr.io/home-assistant/aarch64-base:3.24-2026.06.1 - amd64: ghcr.io/home-assistant/amd64-base:3.24-2026.06.1 diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/dependencies.d/base b/samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/dependencies.d/base deleted file mode 100644 index e69de29bb..000000000 diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/network-interfaces.sh b/samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/network-interfaces.sh deleted file mode 100644 index fa703503c..000000000 --- a/samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/network-interfaces.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/with-contenv bash -# vim: ft=bash -# shellcheck shell=bash - -# Populate the provided array variable with enabled network interfaces. -get_enabled_interfaces() { - local -n _out_interfaces=$1 - local interface - local interface_enabled - - _out_interfaces=() - for interface in $(bashio::network.interfaces); do - interface_enabled=$(bashio::network.enabled "${interface}") - if bashio::var.true "${interface_enabled}"; then - _out_interfaces+=("${interface}") - fi - done -} diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/run b/samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/run deleted file mode 100755 index 28e4633e6..000000000 --- a/samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/run +++ /dev/null @@ -1,97 +0,0 @@ -#!/command/with-contenv bashio -# vim: ft=bash -# shellcheck shell=bash -# ============================================================================== -# Prepare the Samba service for running -# ============================================================================== -declare password -declare username -declare config_username -declare samba_username -declare stored_options -declare migration_payload -declare -a interfaces=() -export HOSTNAME - -# shellcheck disable=SC1091 # Sourced from container filesystem path at runtime. -source /etc/s6-overlay/s6-rc.d/init-smbd/network-interfaces.sh - -# Check Login data -if ! bashio::config.has_value 'username' || ! bashio::config.has_value 'password'; then - bashio::exit.nok "Setting a username and password is required!" -fi - -bashio::config.require "enabled_shares" "Samba is a tool for sharing folders. Starting it without sharing any folders defeats the purpose." - -# Migrate stored enabled_shares values: normalize to lower case and rename the -# legacy `addons`/`addon_configs` share names to `local_apps`/`app_configs` to -# match Home Assistant's app terminology. Values have always been treated -# case-insensitively at runtime; persisting the canonical, renamed form keeps -# the stored configuration current and prepares for a future release that can -# drop the legacy names from the schema. The `addons` and `addon_configs` -# shares stay exposed for backward compatibility (see smb.gtpl). -stored_options=$(bashio::api.supervisor GET /addons/self/info false | jq '.options') -if jq -e '(.enabled_shares // []) | any( - ascii_downcase as $s - | (. != $s) or ($s == "addons") or ($s == "addon_configs") - )' <<< "${stored_options}" > /dev/null; then - bashio::log.info "Migrating enabled_shares configuration values" - migration_payload=$(jq -c ' - def migrate: - (. // []) - | map(ascii_downcase) - | map( - if . == "addons" then "local_apps" - elif . == "addon_configs" then "app_configs" - else . end - ) - | reduce .[] as $s ([]; if index($s) then . else . + [$s] end); - {options: (.enabled_shares |= migrate)} - ' <<< "${stored_options}") - if ! bashio::api.supervisor POST /addons/self/options "${migration_payload}"; then - bashio::log.warning "Could not migrate enabled_shares values; will retry on next start" - fi -fi - -# Read hostname from API or setting default "hassio" -HOSTNAME=$(bashio::info.hostname) -if bashio::var.is_empty "${HOSTNAME}"; then - bashio::log.warning "Can't read hostname, using default." - HOSTNAME="hassio" -fi -bashio::log.info "Hostname: ${HOSTNAME}" - -# Get supported interfaces -get_enabled_interfaces interfaces -if [ ${#interfaces[@]} -eq 0 ]; then - bashio::exit.nok 'No supported interfaces found to bind on.' -fi -bashio::log.info "Interfaces: $(printf '%s ' "${interfaces[@]}")" - -# Generate Samba configuration. -# Use an internal Samba username when the configured username contains spaces. -config_username=$(bashio::config 'username') -samba_username=$(printf '%s' "${config_username}" | tr '[:space:]' '_') -: >/etc/samba/smbusers -if [[ "${config_username}" =~ [[:space:]] ]]; then - { - printf '%s = \"%s\"\n' "${samba_username}" "${config_username//\"/\\\"}" - } >/etc/samba/smbusers -fi - -jq --arg username "${samba_username}" \ - ".interfaces = $(jq -c -n '$ARGS.positional' --args -- "${interfaces[@]}") | - .enabled_shares.[] |= ascii_downcase | - .username = \$username" /data/options.json \ - | tempio \ - -template /usr/share/tempio/smb.gtpl \ - -out /etc/samba/smb.conf - -# Init user -username=${samba_username} -password=$(bashio::config 'password') -addgroup "${username}" -adduser -D -H -G "${username}" -s /bin/false "${username}" - -(echo "$password"; echo "$password") \ - | smbpasswd -a -s -c "/etc/samba/smb.conf" "${username}" diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/type b/samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/type deleted file mode 100644 index bdd22a185..000000000 --- a/samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/type +++ /dev/null @@ -1 +0,0 @@ -oneshot diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/up b/samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/up deleted file mode 100644 index 1abccc03b..000000000 --- a/samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/up +++ /dev/null @@ -1 +0,0 @@ -/etc/s6-overlay/s6-rc.d/init-smbd/run diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/dependencies.d/smbd b/samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/dependencies.d/smbd deleted file mode 100644 index e69de29bb..000000000 diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/finish b/samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/finish deleted file mode 100755 index 25b9f6101..000000000 --- a/samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/finish +++ /dev/null @@ -1,27 +0,0 @@ -#!/command/with-contenv bashio -# vim: ft=bash -# shellcheck shell=bash -# ============================================================================== -# Take down the S6 supervision tree when nmbd fails -# ============================================================================== -# shellcheck disable=SC2155 -readonly exit_code_container=$( /run/s6-linux-init-container-results/exitcode - fi - [[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt -elif [[ "${exit_code_service}" -ne 0 ]]; then - if [[ "${exit_code_container}" -eq 0 ]]; then - echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode - fi - exec /run/s6/basedir/bin/halt -fi diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/run b/samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/run deleted file mode 100755 index 74bb858e8..000000000 --- a/samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/run +++ /dev/null @@ -1,10 +0,0 @@ -#!/command/with-contenv bashio -# vim: ft=bash -# shellcheck shell=bash -# ============================================================================== -# Start nmbd service -# ============================================================================== -exec nmbd \ - --foreground \ - --debug-stdout \ - --no-process-group diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/type b/samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/type deleted file mode 100644 index 5883cff0c..000000000 --- a/samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/type +++ /dev/null @@ -1 +0,0 @@ -longrun diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/dependencies.d/init-smbd b/samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/dependencies.d/init-smbd deleted file mode 100644 index e69de29bb..000000000 diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/finish b/samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/finish deleted file mode 100755 index 4fb2dc554..000000000 --- a/samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/finish +++ /dev/null @@ -1,30 +0,0 @@ -#!/command/with-contenv bashio -# vim: ft=bash -# shellcheck shell=bash -# ============================================================================== -# Take down the S6 supervision tree when smbd fails -# ============================================================================== -# shellcheck disable=SC2155 -readonly exit_code_container=$( /run/s6-linux-init-container-results/exitcode - fi - [[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt -elif [[ "${exit_code_service}" -ne 0 ]]; then - if [[ "${exit_code_container}" -eq 0 ]]; then - echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode - fi - exec /run/s6/basedir/bin/halt -fi diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/run b/samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/run deleted file mode 100755 index 219d3d4eb..000000000 --- a/samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/run +++ /dev/null @@ -1,10 +0,0 @@ -#!/command/with-contenv bashio -# vim: ft=bash -# shellcheck shell=bash -# ============================================================================== -# Start smbd service -# ============================================================================== -exec smbd \ - --foreground \ - --debug-stdout \ - --no-process-group diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/type b/samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/type deleted file mode 100644 index 5883cff0c..000000000 --- a/samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/type +++ /dev/null @@ -1 +0,0 @@ -longrun diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/init-smbd b/samba/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/init-smbd deleted file mode 100644 index e69de29bb..000000000 diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/nmbd b/samba/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/nmbd deleted file mode 100644 index e69de29bb..000000000 diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/smbd b/samba/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/smbd deleted file mode 100644 index e69de29bb..000000000 diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/wsdd b/samba/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/wsdd deleted file mode 100644 index 8b1378917..000000000 --- a/samba/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/wsdd +++ /dev/null @@ -1 +0,0 @@ - diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/wsdd/dependencies.d/init-smbd b/samba/rootfs/etc/s6-overlay/s6-rc.d/wsdd/dependencies.d/init-smbd deleted file mode 100644 index 8b1378917..000000000 --- a/samba/rootfs/etc/s6-overlay/s6-rc.d/wsdd/dependencies.d/init-smbd +++ /dev/null @@ -1 +0,0 @@ - diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/wsdd/finish b/samba/rootfs/etc/s6-overlay/s6-rc.d/wsdd/finish deleted file mode 100755 index 849242a8b..000000000 --- a/samba/rootfs/etc/s6-overlay/s6-rc.d/wsdd/finish +++ /dev/null @@ -1,31 +0,0 @@ -#!/command/with-contenv bashio -# vim: ft=bash -# shellcheck shell=bash -# ============================================================================== -# Keep the addon running when the optional wsdd service fails -# ============================================================================== - -# shellcheck disable=SC2155 -readonly exit_code_container=$( /run/s6-linux-init-container-results/exitcode - fi - exec /run/s6/basedir/bin/halt -elif [[ "${exit_code_service}" -eq 256 ]]; then - bashio::log.warning \ - "Optional service ${service} exited by signal ${exit_code_signal}; continuing without Windows discovery." - exit 125 -elif [[ "${exit_code_service}" -ne 0 ]]; then - bashio::log.warning \ - "Optional service ${service} failed; continuing without Windows discovery." - exit 125 -fi diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/wsdd/run b/samba/rootfs/etc/s6-overlay/s6-rc.d/wsdd/run deleted file mode 100755 index b35085829..000000000 --- a/samba/rootfs/etc/s6-overlay/s6-rc.d/wsdd/run +++ /dev/null @@ -1,42 +0,0 @@ -#!/command/with-contenv bashio -# vim: ft=bash -# shellcheck shell=bash -# ============================================================================== -# Start wsdd service -# ============================================================================== -declare hostname -declare workgroup -declare -a wsdd_interfaces=() -declare -a interfaces=() - -# shellcheck disable=SC1091 # Sourced from container filesystem path at runtime. -source /etc/s6-overlay/s6-rc.d/init-smbd/network-interfaces.sh - -# Match Samba's advertised server name. -hostname=$(bashio::info.hostname) -if bashio::var.is_empty "${hostname}"; then - bashio::log.warning "Can't read hostname, using default." - hostname="hassio" -fi -workgroup=$(bashio::config 'workgroup') -if bashio::var.is_empty "${workgroup}"; then - bashio::log.warning "Can't read workgroup, using default." - workgroup="WORKGROUP" -fi - -get_enabled_interfaces interfaces - -if [ ${#interfaces[@]} -eq 0 ]; then - bashio::log.warning 'WSDD disabled: no supported interfaces found to bind on.' - exit 1 -fi - -# wsdd expects each interface to be preceded by "-i". -for interface in "${interfaces[@]}"; do - wsdd_interfaces+=("-i" "${interface}") -done - -bashio::log.info \ - "Starting the WSDD daemon on interfaces: ${interfaces[*]} for ${workgroup}/${hostname}" - -exec wsdd "${wsdd_interfaces[@]}" -n "${hostname}" -w "${workgroup}" diff --git a/samba/rootfs/etc/s6-overlay/s6-rc.d/wsdd/type b/samba/rootfs/etc/s6-overlay/s6-rc.d/wsdd/type deleted file mode 100644 index 5883cff0c..000000000 --- a/samba/rootfs/etc/s6-overlay/s6-rc.d/wsdd/type +++ /dev/null @@ -1 +0,0 @@ -longrun diff --git a/samba/rootfs/etc/s6-overlay/scripts/enable-check.sh b/samba/rootfs/etc/s6-overlay/scripts/enable-check.sh deleted file mode 100755 index 555be3b2a..000000000 --- a/samba/rootfs/etc/s6-overlay/scripts/enable-check.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/command/with-contenv bashio -# shellcheck shell=bash -# ============================================================================== -# Enable/disable optional services per config -# ============================================================================== -if bashio::config.true 'netbios'; then - touch /etc/s6-overlay/s6-rc.d/user/contents.d/nmbd - bashio::log.info "Service nmbd enabled" -else - rm -f /etc/s6-overlay/s6-rc.d/user/contents.d/nmbd - bashio::log.info "Service nmbd disabled" -fi - -if bashio::config.true 'network_discovery'; then - touch /etc/s6-overlay/s6-rc.d/user/contents.d/wsdd - bashio::log.info "Service wsdd enabled" -else - rm -f /etc/s6-overlay/s6-rc.d/user/contents.d/wsdd - bashio::log.info "Service wsdd disabled" -fi diff --git a/samba/rootfs/usr/share/tempio/smb.gtpl b/samba/rootfs/usr/share/tempio/smb.gtpl deleted file mode 100644 index 9efcae874..000000000 --- a/samba/rootfs/usr/share/tempio/smb.gtpl +++ /dev/null @@ -1,162 +0,0 @@ -[global] - netbios name = {{ env "HOSTNAME" }} - workgroup = {{ .workgroup }} - server string = Samba Home Assistant - local master = {{ .local_master | ternary "yes" "no" }} - - security = user - ntlm auth = yes - idmap config * : backend = tdb - idmap config * : range = 1000000-2000000 - username map = /etc/samba/smbusers - - load printers = no - disable spoolss = yes - - log level = 1 - - bind interfaces only = yes - interfaces = lo {{ .interfaces | join " " }} - hosts allow = 127.0.0.1 {{ .allow_hosts | join " " }} - - {{ if .compatibility_mode }} - client min protocol = NT1 - server min protocol = NT1 - {{ end }} - - mangled names = no - dos charset = CP850 - unix charset = UTF-8 - - {{ if .apple_compatibility_mode }} - vfs objects = catia fruit streams_xattr - {{ end }} - - {{ if not .netbios }} - smb ports = 445 - {{ end }} - - server signing = {{ .server_signing }} - - kernel oplocks = yes - -{{ if (has "config" .enabled_shares) }} -[config] - browseable = yes - writeable = yes - path = /homeassistant - - valid users = {{ .username }} - force user = root - force group = root - veto files = /{{ .veto_files | join "/" }}/ - delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }} -{{ end }} - -{{ if or (has "local_apps" .enabled_shares) (has "addons" .enabled_shares) }} -[local_apps] - browseable = yes - writeable = yes - path = /local_apps - - valid users = {{ .username }} - force user = root - force group = root - veto files = /{{ .veto_files | join "/" }}/ - delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }} -{{ end }} - -{{ if or (has "local_apps" .enabled_shares) (has "addons" .enabled_shares) }} -[addons] - browseable = yes - writeable = yes - path = /local_apps - preexec = /usr/bin/logger -s -t smbd -p local0.warning "%u connected to deprecated share %S from %m (%I), please switch to the local_apps share" - - valid users = {{ .username }} - force user = root - force group = root - veto files = /{{ .veto_files | join "/" }}/ - delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }} -{{ end }} - -{{ if or (has "app_configs" .enabled_shares) (has "addon_configs" .enabled_shares) }} -[app_configs] - browseable = yes - writeable = yes - path = /app_configs - - valid users = {{ .username }} - force user = root - force group = root - veto files = /{{ .veto_files | join "/" }}/ - delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }} -{{ end }} - -{{ if or (has "app_configs" .enabled_shares) (has "addon_configs" .enabled_shares) }} -[addon_configs] - browseable = yes - writeable = yes - path = /app_configs - preexec = /usr/bin/logger -s -t smbd -p local0.warning "%u connected to deprecated share %S from %m (%I), please switch to the app_configs share" - - valid users = {{ .username }} - force user = root - force group = root - veto files = /{{ .veto_files | join "/" }}/ - delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }} -{{ end }} - -{{ if (has "ssl" .enabled_shares) }} -[ssl] - browseable = yes - writeable = yes - path = /ssl - - valid users = {{ .username }} - force user = root - force group = root - veto files = /{{ .veto_files | join "/" }}/ - delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }} -{{ end }} - -{{ if (has "share" .enabled_shares) }} -[share] - browseable = yes - writeable = yes - path = /share - - valid users = {{ .username }} - force user = root - force group = root - veto files = /{{ .veto_files | join "/" }}/ - delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }} -{{ end }} - -{{ if (has "backup" .enabled_shares) }} -[backup] - browseable = yes - writeable = yes - path = /backup - - valid users = {{ .username }} - force user = root - force group = root - kernel oplocks = no - veto files = /{{ .veto_files | join "/" }}/ - delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }} -{{ end }} - -{{ if (has "media" .enabled_shares) }} -[media] - browseable = yes - writeable = yes - path = /media - - valid users = {{ .username }} - force user = root - force group = root - kernel oplocks = no - veto files = /{{ .veto_files | join "/" }}/ - delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }} -{{ end }}