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:
@@ -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`
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user