fix: share smb-server share warns on Samba-passdb gaps + blocked parent traversal

share now checks both common NT_STATUS_ACCESS_DENIED causes before writing the
config (warnings only — the share is still applied):
- --users entries missing from the Samba passdb (pdbedit -L) get a warning
  pointing at 'pos share smb-server adduser <user>' — valid users = <u> with
  no Samba password previously failed for clients with no clue why.
- every ancestor of the share path is checked for other:+x traversal (sticky
  dirs like /tmp count as traversable); a 700 home dir under the share path
  now warns with 'chmod o+x <dir>'.
Docs: howto/share.md SMB section + NT_STATUS_ACCESS_DENIED troubleshooting.
Verified with a stub-PATH suite (pdbedit/systemctl/smbcontrol/testparm stubs,
SMB_CONF seam): 16/16 green.
This commit is contained in:
Your Name
2026-08-13 02:14:36 -04:00
parent 414a990801
commit 5da148ac4e
3 changed files with 101 additions and 0 deletions
+9
View File
@@ -179,6 +179,11 @@ can then access them; print the restricted form with `--users`.
SMB shares need Samba accounts, not just system users: `adduser <user>` SMB shares need Samba accounts, not just system users: `adduser <user>`
(prompts for the password via `smbpasswd -a`) after the system user exists. (prompts for the password via `smbpasswd -a`) after the system user exists.
`share --users u1,u2` checks the list against the Samba passdb and warns about
any missing account (pointing at `adduser`) — plus it walks the path's parent
dirs and warns when one lacks `other:+x` traversal (e.g. a `700` home dir
blocks Samba clients with `NT_STATUS_ACCESS_DENIED`; fix with `chmod o+x`).
Both are warnings only — the share is still written.
**Recipes:** **Recipes:**
- **Share the media drive to the tailnet (users bob + alice):** - **Share the media drive to the tailnet (users bob + alice):**
@@ -196,6 +201,10 @@ SMB shares need Samba accounts, not just system users: `adduser <user>`
- "smbd not found" → `samba` isn't installed; `sudo apt install samba` - "smbd not found" → `samba` isn't installed; `sudo apt install samba`
- Windows can't connect → check the client is in `--users` / has a Samba - Windows can't connect → check the client is in `--users` / has a Samba
password (`adduser`), and that `smbd` is running (`status`) password (`adduser`), and that `smbd` is running (`status`)
- `NT_STATUS_ACCESS_DENIED` → two causes, `share` warns about both at share
time: the user is not in the Samba passdb (`pos share smb-server adduser <user>`),
or a parent dir of the share path lacks `other:+x` traversal (`chmod o+x <dir>`
— typical for `700` home dirs)
- `valid users` users can't log in → their Samba password differs from the - `valid users` users can't log in → their Samba password differs from the
system one; re-run `pos share smb server adduser <user>` system one; re-run `pos share smb server adduser <user>`
- After editing `/etc/samba/smb.conf` by hand, run `pos share smb server reload` - After editing `/etc/samba/smb.conf` by hand, run `pos share smb server reload`
+27
View File
@@ -67,6 +67,31 @@ validate_share_name() {
esac esac
} }
# Warn when any ancestor of the share path lacks other:+x — Samba clients
# traverse as the authenticated user, so a 700 home dir yields
# NT_STATUS_ACCESS_DENIED no matter what smb.conf says. (Sticky dirs like
# /tmp show 't' in the other-execute slot — still traversable.)
check_traversal() {
local p="$1" blocked="" m
while [ "$p" != "/" ]; do
m="$(stat -c '%A' "$p" 2>/dev/null | cut -c10)"
[ "$m" = "x" ] || [ "$m" = "t" ] || blocked="${blocked:+$blocked, }$p"
p="$(dirname "$p")"
done
[ -z "$blocked" ] || warn "Samba can't traverse: $blocked (missing other:+x) — clients get NT_STATUS_ACCESS_DENIED. Fix: chmod o+x <dir>"
}
# Warn for --users entries missing from the Samba passdb (pdbedit/smbpasswd).
check_samba_users() {
local list="$1" sdb u missing=""
if sdb="$(sudo pdbedit -L 2>/dev/null | cut -d: -f1)"; then
for u in ${list//,/ }; do
grep -qxF "$u" <<<"$sdb" || missing="${missing:+$missing, }$u"
done
fi
[ -z "$missing" ] || warn "user(s) not in the Samba passdb: $missing — clients get NT_STATUS_ACCESS_DENIED. Add them: pos share smb-server adduser <user> (needs a system user)"
}
# Validate smb.conf with testparm, then hot-reload smbd if it is running. # Validate smb.conf with testparm, then hot-reload smbd if it is running.
reload_config() { reload_config() {
testparm -s "$SMB_CONF" >/dev/null || err "smb.conf is invalid — changes not loaded (fix with 'pos share smb-server reload')" testparm -s "$SMB_CONF" >/dev/null || err "smb.conf is invalid — changes not loaded (fix with 'pos share smb-server reload')"
@@ -110,6 +135,7 @@ case "$cmd" in
-*) err "Usage: pos share smb-server share <path> [name] [--read-only|--guest|--users u1,u2]" ;; -*) err "Usage: pos share smb-server share <path> [name] [--read-only|--guest|--users u1,u2]" ;;
esac esac
require_root_dir "$path" require_root_dir "$path"
check_traversal "$path"
[ -f "$SMB_CONF" ] || err "No smb.conf at $SMB_CONF (is samba installed?)" [ -f "$SMB_CONF" ] || err "No smb.conf at $SMB_CONF (is samba installed?)"
shift 2 shift 2
@@ -131,6 +157,7 @@ case "$cmd" in
elif [ -z "$users" ]; then elif [ -z "$users" ]; then
warn "No valid users — any Samba account can access $path. Restrict with --users u1,u2." warn "No valid users — any Samba account can access $path. Restrict with --users u1,u2."
fi fi
[ -n "$users" ] && check_samba_users "$users"
ro_val=no; [ "$ro" -eq 1 ] && ro_val=yes ro_val=no; [ "$ro" -eq 1 ] && ro_val=yes
guest_val=no; [ "$guest" -eq 1 ] && guest_val=yes guest_val=no; [ "$guest" -eq 1 ] && guest_val=yes
@@ -0,0 +1,65 @@
Here is a concise bug report you can hand off to the developers of `pos` (or use to fix the script if you maintain it yourself).
---
## 🐛 Bug Report: `pos share smb-server` Creates Inaccessible Shares
### **Issue Description**
When adding a share with `pos share smb-server share <path> --users <user>`, the command successfully adds the share to `/etc/samba/smb.conf` and reloads `smbd`. However, clients receive `NT_STATUS_ACCESS_DENIED` upon connecting.
---
### **Root Causes**
1. **Missing Samba User Credentials (`smbpasswd`)**
* **Problem:** `pos` configures `valid users = <user>` in `smb.conf`, but fails to initialize or sync the user in Samba's passdb (`passdb.tdb`). Standard Linux account credentials in `/etc/shadow` are not recognized by Samba without `smbpasswd`.
* **Result:** Samba rejects authentication or tree connection requests.
2. **Parent Directory Permission Lockdown**
* **Problem:** When sharing a path inside a user's home directory (e.g., `/home/username/shared`), default Linux home permissions are set to `700` (`drwx------`). Samba cannot traverse `/home/username` to reach `/home/username/shared`.
* **Result:** `NT_STATUS_ACCESS_DENIED` due to missing `+x` (traversal) permission on parent directories.
---
### **Proposed Fixes for `pos` CLI**
#### **Fix 1: Register User in Samba Database**
When `--users <user>` is passed, check if the user exists in `pdbedit -L`. If missing, prompt for a Samba password or run:
```bash
sudo smbpasswd -a <user>
sudo smbpasswd -e <user>
```
#### **Fix 2: Automate Parent Directory Traversal Sanity Check**
Before adding a share path (e.g., `/home/user/share`), inspect parent directory permissions. If `others` lack execution rights (`+x`), automatically run or prompt:
```bash
chmod o+x /home/<user>
```
---
### **Workaround (Manual Fix)**
To fix the share created by `pos` right now, run:
```bash
# 1. Set traversal rights on home directory
chmod o+x /home/unknown
# 2. Add user to Samba database
sudo smbpasswd -a unknown
# 3. Restart Samba daemon
sudo systemctl restart smbd
```