whycant 0.1.0

CLI tool to figure out why you can't do something.
Documentation

whycant

Explain, with evidence, why a filesystem operation is denied for a chosen identity.

What it does

Walks every access-control layer a Unix kernel consults, in order, and evaluates each against a target identity (uid, primary gid, full supplementary group set) rather than the current euid:

  • ancestor traverse (+x)
  • DAC mode/owner
  • POSIX/NFSv4 ACL
  • immutable and append attrs
  • mount flags (ro/noexec)
  • Linux MAC/LSM (SELinux, AppArmor, SMACK/TOMOYO)
  • capabilities
  • network-FS (NFS/CIFS root_squash, ro-export, uid mismatch)
  • container/userns
  • macOS SIP, quarantine, TCC

Names what first denies the operation, shows the raw evidence line behind the verdict, and prints the exact least-privilege fix. Anything computable unprivileged is proven; a MAC denial provable only from the audit log is suspected until confirmed with sudo.

Install

cargo install whycant

From source:

# Linux needs libacl for the ACL layer
sudo apt-get install -y libacl1-dev
cargo build --release
# ACL layer is optional; build without exacl/libacl:
cargo build --release --no-default-features

Man page:

whycant --man > whycant.1
sudo cp whycant.1 /usr/local/share/man/man1/whycant.1
man whycant

Usage

whycant read /srv/data/report.txt          # explicit op + path
whycant /srv/data                          # bare path, op inferred (dir -> traverse)
whycant --user www-data read /srv/share/x  # evaluate on behalf of another user
whycant -- cat /etc/shadow                 # wrap a command, infer op + target
whycant --json read /srv/data/report.txt   # machine output on stdout
whycant -v write /home/alice/secret.txt    # --all: every layer, including pass/skip

Sample output

✗ BLOCKED  traverse /srv/data/report.txt   /srv/data not traversable by alice

  /           ✓ x
  srv         ✓ x
  data        ✗ x  drwxr-x--- 4 root staff 4096 /srv/data   others lack x; alice not in group staff
  report.txt  ·   not reached

traverse denied at /srv/data
  ls -ld  drwxr-x--- 4 root staff 4096 /srv/data

  → sudo chmod 'o+x' /srv/data   [risk: low]
      others need +x to descend into /srv/data toward report.txt

Exit codes

Code Meaning
0 allowed; nothing denies the operation
1 blocked, cause proven
2 blocked but indeterminate; needs privilege to confirm
3 target error (ENOENT, not a regular file, broken symlink)
64 usage error

Output formats

  • human (default) glyph verdict, vertical evidence chain, raw lines, fixes; banner on stderr.
  • plain (--format plain) ASCII marks, stable columns, one record per line for grep/awk.
  • json (--json) one Report on stdout, no banner, identity/privilege folded in.
  • toml (--toml) same Report, TOML encoding.

Platform matrix

Layer Linux FreeBSD macOS
existence, traverse, DAC yes yes yes
ACL POSIX (exacl) NFSv4/POSIX NFSv4
attrs FS_IOC_GETFLAGS st_flags st_flags
mount statvfs + /proc/mounts statfs MNT_* statfs + ro system volume
capabilities yes skip skip
MAC/LSM SELinux, AppArmor, SMACK/TOMOYO mac(4) presence skip
macOS SIP/quarantine/TCC skip skip yes
network-FS yes yes yes
container/userns yes skip skip

Inapplicable layers report skip so the chain and exit-code mapping stay identical across platforms.