diff --git a/readme.md b/readme.md index a995d62..3952fb6 100644 --- a/readme.md +++ b/readme.md @@ -39,24 +39,45 @@ docker run -it --rm -p 445:445 -e "USER=samba" -e "PASS=secret" -v "/home/exampl ## Configuration ⚙️ - * ### How do I modify the credentials? +### How do I modify the credentials? - You can set the `USER` and `PASS` environment variables to modify the credentials from their default values: user `samba` with password `secret`. +You can set the `USER` and `PASS` environment variables to modify the credentials from their default values: user `samba` with password `secret`. - * ### How do I modify the permissions? +### How do I modify the permissions? - You can set `UID` and `GID` environment variables to change the user and group ID. +You can set `UID` and `GID` environment variables to change the user and group ID. - To mark the share as read-only, add the variable `RW: false`. +To mark the share as read-only, add the variable `RW: false`. - * ### How do I modify other settings? +### How do I modify other settings? - If you need more advanced features, you can completely override the default configuration by modifying the [smb.conf](https://github.com/dockur/samba/blob/master/smb.conf) file in this repo, and binding your custom config to the container like this: +If you need more advanced features, you can completely override the default configuration by modifying the [smb.conf](https://github.com/dockur/samba/blob/master/smb.conf) file in this repo, and binding your custom config to the container like this: - ```yaml - volumes: - - /example/smb.conf:/etc/samba/smb.conf - ``` +```yaml +volumes: + - /example/smb.conf:/etc/samba/smb.conf +``` + +### How do I use multiple users? + +If you want to use multiple Samba users, you can enable multi-user mode by binding the [smb_user.conf](https://github.com/dockur/samba/blob/master/smb_user.conf) file to the container as follows: + +```yaml +volumes: + - /example/smb.conf:/etc/samba/smb.conf + - /example/smb_user.conf:/etc/samba/smb_user.conf +``` + +You can also modify the [smb.conf](https://github.com/dockur/samba/blob/master/smb.conf) to implement different Samba policies for different users. + +> [!NOTE] +> In this mode, you will need to manage the ownership and permissions of the shared folders yourself. +> +> In the [smb_user.conf](https://github.com/dockur/samba/blob/master/smb_user.conf) file, user configurations must follow a specific format. Each line should contain the user information in the following order: +>```yaml +>username:uid:groupname:gid:password +>``` +>Each line represents the configuration for a single user, and the parameters must be separated by colons. ## Stars 🌟 [![Stars](https://starchart.cc/dockur/samba.svg?variant=adaptive)](https://starchart.cc/dockur/samba) diff --git a/samba.sh b/samba.sh index 11bce56..6cf505d 100644 --- a/samba.sh +++ b/samba.sh @@ -1,84 +1,144 @@ #!/usr/bin/env bash set -Eeuo pipefail -# Set variables for group and share directory -group="smb" -share="/storage" -secret="/run/secrets/pass" +# This function checks for the existence of a specified Samba user and group. If the user does not exist, +# it creates a new user with the provided username, user ID (UID), group name, group ID (GID), and password. +# If the user already exists, it updates the user's UID and group association as necessary, +# and updates the password in the Samba database. The function ensures that the group also exists, +# creating it if necessary, and modifies the group ID if it differs from the provided value. +add_user() { + local username="$1" + local uid="$2" + local groupname="$3" + local gid="$4" + local password="$5" + + # Check if the smb group exists, if not, create it + if ! getent group "$groupname" &>/dev/null; then + echo "Group $groupname does not exist, creating group..." + groupadd -o -g "$gid" "$groupname" || { echo "Failed to create group $groupname"; return 1; } + else + # Check if the gid right,if not, change it + local current_gid + current_gid=$(getent group "$groupname" | cut -d: -f3) + if [[ "$current_gid" != "$gid" ]]; then + echo "Group $groupname exists but GID differs, updating GID..." + groupmod -o -g "$gid" "$groupname" || { echo "Failed to update GID for group $groupname"; return 1; } + fi + fi -# Create shared directory -mkdir -p "$share" || { echo "Failed to create directory $share"; exit 1; } + # Check if the user already exists, if not, create it + if ! id "$username" &>/dev/null; then + echo "User $username does not exist, creating user..." + adduser -S -D -H -h /tmp -s /sbin/nologin -G "$groupname" -u "$uid" -g "Samba User" "$username" || { echo "Failed to create user $username"; return 1; } + else + # Check if the uid right,if not, change it + local current_uid + current_uid=$(id -u "$username") + if [[ "$current_uid" != "$uid" ]]; then + echo "User $username exists but UID differs, updating UID..." + usermod -o -u "$uid" "$username" || { echo "Failed to update UID for user $username"; return 1; } + fi -# Check if the smb group exists, if not, create it -if ! getent group "$group" &>/dev/null; then - groupadd "$group" || { echo "Failed to create group $group"; exit 1; } -fi + # Update user's group + usermod -g "$groupname" "$username" || { echo "Failed to update group for user $username"; return 1; } + fi -# Check if the user already exists, if not, create it -if ! id "$USER" &>/dev/null; then - adduser -S -D -H -h /tmp -s /sbin/nologin -G "$group" -g 'Samba User' "$USER" || { echo "Failed to create user $USER"; exit 1; } -fi + # Check if the user is a samba user + if pdbedit -L | grep -q "^$username:"; then + # if the user is a samba user, change its password + echo -e "$password\n$password" | smbpasswd -s "$username" || { echo "Failed to update Samba password for $username"; return 1; } + echo "Password for existing Samba user $username has been updated." + else + # if the user is not a samba user, create it and set a password + echo -e "$password\n$password" | smbpasswd -a -s "$username" || { echo "Failed to add Samba user $username"; return 1; } + echo "User $username has been added to Samba and password set." + fi +} -# Get the current user and group IDs -OldUID=$(id -u "$USER") -OldGID=$(getent group "$group" | cut -d: -f3) +# External config file +config="/etc/samba/smb.conf" +user_config="/etc/samba/smb_user.conf" -# Change the UID and GID of the user and group if necessary -if [[ "$OldUID" != "$UID" ]]; then - usermod -o -u "$UID" "$USER" || { echo "Failed to change UID for $USER"; exit 1; } +# Check if the user configuration file exists +if [[ -f "$user_config" ]] && [[ ! -f "$config" ]]; then + echo "File $config not found, disabling multi-user mode." fi -if [[ "$OldGID" != "$GID" ]]; then - groupmod -o -g "$GID" "$group" || { echo "Failed to change GID for group $group"; exit 1; } -fi +# Check if multi-user mode is enabled +if [[ -f "$user_config" ]] && [[ -f "$config" ]]; then -# Check if an external config file was supplied -config="/etc/samba/smb.conf" + while read -r line; do -if [ -f "$config" ]; then + # Skip lines that are comments or empty + [[ "$line" =~ ^#.*$ || -z "$line" ]] && continue - # Inform the user we are using a custom configuration file. - echo "Using provided configuration file: $config." + # Split each line by colon and assign to variables + username=$(echo "$line" | cut -d':' -f1) + uid=$(echo "$line" | cut -d':' -f2) + groupname=$(echo "$line" | cut -d':' -f3) + gid=$(echo "$line" | cut -d':' -f4) + password=$(echo "$line" | cut -d':' -f5) -else + # Check if all required fields are present + if [[ -z "$username" || -z "$uid" || -z "$groupname" || -z "$gid" || -z "$password" ]]; then + echo "Skipping incomplete line: $line" + continue + fi - config="/etc/samba/smb.tmp" - template="/etc/samba/smb.default" + # Call the function with extracted values + add_user "$username" "$uid" "$groupname" "$gid" "$password" - # Generate a config file from template - rm -f "$config" - cp "$template" "$config" + done < "$user_config" - # Update force user and force group in smb.conf - sed -i "s/^\(\s*\)force user =.*/\1force user = $USER/" "$config" - sed -i "s/^\(\s*\)force group =.*/\1force group = $group/" "$config" +else - # Verify if the RW variable is equal to false (indicating read-only mode) - if [[ "$RW" == [Ff0]* ]]; then + # Set variables for group and share directory + group="smb" + share="/storage" + secret="/run/secrets/pass" - # Adjust settings in smb.conf to set share to read-only - sed -i "s/^\(\s*\)writable =.*/\1writable = no/" "$config" - sed -i "s/^\(\s*\)read only =.*/\1read only = yes/" "$config" + # Create shared directory + mkdir -p "$share" || { echo "Failed to create directory $share"; exit 1; } - else + # Check if the secret file exists and if its size is greater than zero + if [ -s "$secret" ]; then + PASS=$(cat "$secret") + fi - # Set permissions for share directory if new (empty), leave untouched if otherwise - if [ -z "$(ls -A "$share")" ]; then - chmod 0770 "$share" || { echo "Failed to set permissions for directory $share"; exit 1; } - chown "$USER:$group" "$share" || { echo "Failed to set ownership for directory $share"; exit 1; } - fi + add_user "$USER" "$UID" "$group" "$GID" "$PASS" + if [ -f "$config" ]; then + # Inform the user we are using a custom configuration file. + echo "Using provided configuration file: $config." + else + config="/etc/samba/smb.tmp" + template="/etc/samba/smb.default" + + # Generate a config file from template + rm -f "$config" + cp "$template" "$config" + + # Update force user and force group in smb.conf + sed -i "s/^\(\s*\)force user =.*/\1force user = $USER/" "$config" + sed -i "s/^\(\s*\)force group =.*/\1force group = $group/" "$config" + + # Verify if the RW variable is equal to false (indicating read-only mode) + if [[ "$RW" == [Ff0]* ]]; then + # Adjust settings in smb.conf to set share to read-only + sed -i "s/^\(\s*\)writable =.*/\1writable = no/" "$config" + sed -i "s/^\(\s*\)read only =.*/\1read only = yes/" "$config" + else + # Set permissions for share directory if new (empty), leave untouched if otherwise + if [ -z "$(ls -A "$share")" ]; then + chmod 0770 "$share" || { echo "Failed to set permissions for directory $share"; exit 1; } + chown "$USER:$group" "$share" || { echo "Failed to set ownership for directory $share"; exit 1; } + fi + fi fi -fi -# Check if the secret file exists and if its size is greater than zero -if [ -s "$secret" ]; then - PASS=$(cat "$secret") fi -# Change Samba password -echo -e "$PASS\n$PASS" | smbpasswd -a -c "$config" -s "$USER" > /dev/null || { echo "Failed to change Samba password for $USER"; exit 1; } - # Start the Samba daemon with the following options: # --foreground: Run in the foreground instead of daemonizing. # --debug-stdout: Send debug output to stdout. diff --git a/smb_user.conf b/smb_user.conf new file mode 100644 index 0000000..d9560aa --- /dev/null +++ b/smb_user.conf @@ -0,0 +1,2 @@ +#username:UID:groupname:GID:password +samba:1000:smb:1000:secret \ No newline at end of file