add user/samba restore script + yireh and isaac smb shares
This commit is contained in:
Executable
+137
@@ -0,0 +1,137 @@
|
||||
#!/bin/bash
|
||||
# Recreate human users + groups with stable UIDs/GIDs, and restore the
|
||||
# samba passdb from USB backup. Run during recovery BEFORE the data rsync
|
||||
# so file ownership lands on the right UIDs.
|
||||
#
|
||||
# UIDs/GIDs MUST match what the original system used, or ZFS files end up
|
||||
# owned by orphan numeric IDs. The script aborts loudly if it finds an
|
||||
# existing user/group with a different UID/GID than expected — investigate
|
||||
# and either rename the conflicting entry or update the constants below.
|
||||
#
|
||||
# Verify on a live system with:
|
||||
# id timothykim # check uid + primary gid
|
||||
# getent group sambagroup # check sambagroup gid
|
||||
set -euo pipefail
|
||||
|
||||
[ "$EUID" -eq 0 ] || { echo "must run as root" >&2; exit 1; }
|
||||
|
||||
SAMBAGROUP_GID=1001
|
||||
|
||||
# Format: username:uid:gid:shell:home_flag:supp_groups
|
||||
# - gid: numeric gid for the user's primary group (group name = username)
|
||||
# - home_flag: "home" creates /home/<user>, "nohome" skips it (samba-only)
|
||||
# - supp_groups: comma-separated supplementary groups, or "-" for none
|
||||
USERS=(
|
||||
"timothykim:1000:1000:/bin/bash:home:wheel,video,docker,sambagroup"
|
||||
"yireh:1100:1100:/sbin/nologin:nohome:sambagroup"
|
||||
"isaac:1101:1101:/sbin/nologin:nohome:sambagroup"
|
||||
)
|
||||
|
||||
# Abort if an existing entity's numeric ID doesn't match what we expect
|
||||
assert_match() {
|
||||
local label=$1 expected=$2 actual=$3
|
||||
if [ "$expected" != "$actual" ]; then
|
||||
echo "[FATAL] $label mismatch: expected $expected, got $actual" >&2
|
||||
echo " ZFS file ownership will break if you proceed." >&2
|
||||
echo " Either rename the conflicting entry or update this script." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
echo "=== sambagroup ==="
|
||||
if getent group sambagroup &>/dev/null; then
|
||||
actual=$(getent group sambagroup | cut -d: -f3)
|
||||
assert_match "sambagroup gid" "$SAMBAGROUP_GID" "$actual"
|
||||
echo "[ok] sambagroup exists (gid $actual)"
|
||||
else
|
||||
groupadd -g "$SAMBAGROUP_GID" sambagroup
|
||||
echo "[+] created sambagroup (gid $SAMBAGROUP_GID)"
|
||||
fi
|
||||
|
||||
# Preflight: every supplementary group referenced must already exist.
|
||||
# wheel/video are OS-default; docker is created by docker-ce install (RUNBOOK
|
||||
# step 2); sambagroup was just handled above. If anything's missing, abort
|
||||
# before touching users — half-applied group memberships are annoying to undo.
|
||||
echo ""
|
||||
echo "=== preflight: supplementary groups ==="
|
||||
missing=()
|
||||
for entry in "${USERS[@]}"; do
|
||||
supp=$(echo "$entry" | cut -d: -f6)
|
||||
[ "$supp" = "-" ] && continue
|
||||
IFS=, read -ra groups <<< "$supp"
|
||||
for g in "${groups[@]}"; do
|
||||
if ! getent group "$g" &>/dev/null; then
|
||||
missing+=("$g")
|
||||
fi
|
||||
done
|
||||
done
|
||||
if [ ${#missing[@]} -gt 0 ]; then
|
||||
# de-dupe for a cleaner error message
|
||||
uniq_missing=$(printf '%s\n' "${missing[@]}" | sort -u | tr '\n' ' ')
|
||||
echo "[FATAL] required supplementary groups missing: $uniq_missing" >&2
|
||||
echo " likely cause: a package that creates the group hasn't been" >&2
|
||||
echo " installed yet (e.g., docker-ce creates the docker group)." >&2
|
||||
echo " complete RUNBOOK step 2 before running this script." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "[ok] all supplementary groups present"
|
||||
|
||||
for entry in "${USERS[@]}"; do
|
||||
IFS=: read -r u uid gid shell home_flag supp <<< "$entry"
|
||||
echo ""
|
||||
echo "=== $u ==="
|
||||
|
||||
# Primary group (same name as user, pinned GID — pre-created so useradd
|
||||
# doesn't auto-assign one via USERGROUPS_ENAB)
|
||||
if getent group "$u" &>/dev/null; then
|
||||
actual=$(getent group "$u" | cut -d: -f3)
|
||||
assert_match "$u primary group gid" "$gid" "$actual"
|
||||
echo "[ok] group $u exists (gid $actual)"
|
||||
else
|
||||
groupadd -g "$gid" "$u"
|
||||
echo "[+] created group $u (gid $gid)"
|
||||
fi
|
||||
|
||||
# User account
|
||||
if id "$u" &>/dev/null; then
|
||||
actual_uid=$(id -u "$u")
|
||||
actual_gid=$(id -g "$u")
|
||||
assert_match "$u uid" "$uid" "$actual_uid"
|
||||
assert_match "$u primary gid" "$gid" "$actual_gid"
|
||||
echo "[ok] $u exists (uid $actual_uid, gid $actual_gid)"
|
||||
else
|
||||
if [ "$home_flag" = "home" ]; then
|
||||
useradd -u "$uid" -g "$gid" -s "$shell" -m "$u"
|
||||
else
|
||||
useradd -u "$uid" -g "$gid" -s "$shell" -M "$u"
|
||||
fi
|
||||
echo "[+] created $u (uid $uid, gid $gid)"
|
||||
fi
|
||||
|
||||
# Supplementary groups (idempotent — usermod -aG won't error on duplicates)
|
||||
if [ "$supp" != "-" ]; then
|
||||
usermod -aG "$supp" "$u"
|
||||
echo "[+] $u in supplementary groups: $supp"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=== samba passdb ==="
|
||||
if ! mountpoint -q /mnt/backup; then
|
||||
echo "[!] /mnt/backup is not mounted — skipping samba passdb restore"
|
||||
echo " mount the USB backup drive (RUNBOOK step 5) and re-run if you want"
|
||||
echo " to restore preserved SMB passwords; otherwise set them manually:"
|
||||
echo " for u in timothykim yireh isaac; do smbpasswd -a \"\$u\"; done"
|
||||
elif [ -f /mnt/backup/samba-private/passdb.tdb ]; then
|
||||
install -d -m 700 /var/lib/samba/private
|
||||
cp /mnt/backup/samba-private/*.tdb /var/lib/samba/private/
|
||||
chmod 600 /var/lib/samba/private/*.tdb
|
||||
echo "[+] restored samba passdb from /mnt/backup/samba-private/"
|
||||
else
|
||||
echo "[!] no samba passdb backup found at /mnt/backup/samba-private/"
|
||||
echo " run: for u in timothykim yireh isaac; do smbpasswd -a \"\$u\"; done"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Done ==="
|
||||
echo "Next: set timothykim's Linux login password if not already (passwd timothykim)"
|
||||
Reference in New Issue
Block a user