https://github.com/doas-utils/doasudo
A POSIX shell shim that translates sudo(8) invocations to doas(1)
https://github.com/doas-utils/doasudo
doas posix shell shim sudo
Last synced: 1 day ago
JSON representation
A POSIX shell shim that translates sudo(8) invocations to doas(1)
- Host: GitHub
- URL: https://github.com/doas-utils/doasudo
- Owner: doas-utils
- License: mit
- Created: 2026-03-11T19:08:08.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-05-31T20:57:51.000Z (3 days ago)
- Last Synced: 2026-05-31T22:21:08.602Z (3 days ago)
- Topics: doas, posix, shell, shim, sudo
- Language: Shell
- Homepage:
- Size: 340 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# doasudo
A POSIX shell shim that translates `sudo(8)` invocations to `doas(1)`, with full option coverage, POSIX-safe argument parsing, and security hardening. Drop it in as `sudo` on systems where doas is the privilege escalation tool; scripts that call `sudo` (mostly) work without modification.
Inspired by [jirutka/doas-sudo-shim](https://github.com/jirutka/doas-sudo-shim) (if you don't need edit-mode support and want a minimal translation layer, consider this as an option).
Compatibility: Linux, FreeBSD, OpenBSD, NetBSD, DragonFly BSD, macOS
---
## Supported options
| sudo option | Notes |
|-------------|-------|
| `-u USER` | passed through to doas |
| `-n` | passed through to doas |
| `-H` | sets `HOME` to the target user's passwd entry |
| `-i` | login shell via target user's passwd entry |
| `-s` | shell via `$SHELL` or invoking user's passwd entry |
| `-e` / `sudoedit` / `editas` | edit mode for unprivileged invokers; see below |
| `-k` | clears doas auth (`doas -L`); with a command, runs it afterward |
| `-K` | clears doas auth (`doas -L`); no command or other options permitted |
| `-l` | prints a "not supported" notice |
| `-v` | validates via `doas true` (honors `-n`/`-u`); best-effort, fails closed |
| `-E`, `-A`, `-S`, `-D`, `-R` | warned and ignored |
| `-b`, `-g` | fatal; see `sudo --help` for rationale |
`SUDO_UID`, `SUDO_GID`, `SUDO_USER`, `SUDO_HOME`, and `SUDO_TTY` are set for the target process. The shim provides no support for `SUDO_COMMAND`; programs in the shim call stack will see it unset.
### `doas.conf` requirement
The shim requires a broad, non-`cmd`-scoped doas rule. For example:
```
permit :wheel
```
Restrictive `cmd`-scoped rules are not supported. For instance, granting edit mode under one requires adding unrestricted shell access; use doas directly with a narrowly scoped editor rule instead.
---
## Edit mode
When invoked as `sudo -e`, `sudoedit`, or `editas`, the shim copies target files to a temporary directory owned by the invoking user, runs the editor unprivileged, then writes back any changed files as the privileged user.
Each file is processed in a separate editor session and written back independently, unlike real `sudoedit(8)`, which opens all files at once. For the common single-file case the behavior is identical.
The editor is taken from `$SUDO_EDITOR`, `$VISUAL`, `$EDITOR`, or `vi`. It must be a *single absolute path* (no spaces, tabs, or flags). To pass options to the editor (e.g. `vim -u NONE`), use a wrapper script:
```sh
# /usr/local/bin/vim-sudoedit
#!/bin/sh
exec /usr/bin/vim -u NONE "$@"
```
Then set `SUDO_EDITOR=/usr/local/bin/vim-sudoedit`. See `sudo --help`.
Edit mode can be opted out at build time (see [Installation](#installation)).
### `editas`
The shim installs `editas` alongside `sudoedit`. The name `doasedit` already exists in the wild, but `editas` mirrors doas naming better: *edit as [user]*.
### Restrictions
- Symbolic links may not be edited.
- Files in a user-writable directory may not be edited.
- Device files may not be edited.
- Edit mode may not be invoked by root.
### Security model
Two attack families in edit mode are in scope. *Symlink substitution:* an attacker replaces a path component or the target with a symlink, so the privileged write-back lands on the wrong file. *Temp-file substitution:* the unprivileged working copy is replaced or modified during the edit session so unexpected content reaches the real target during privileged write-back. A set of mitigations address these; the full security model is documented in the `SECURITY NOTE` at the top of `doasudo.in`.
### Optional (paranoid) edit-mode broker
The default edit mode does not prevent same-UID exposure for the lifetime of the editor session. An optional broker keeps the working copy and editor policy outside the invoking user's tree, and returns edited bytes through a framed protocol; privileged write-back is unchanged. Enable with `DOASUDO_EDIT_BROKER=1`; for installation and security details see: [broker/README.md](broker/README.md).
### Optional diffs before saving changes
Setting `DOASUDO_CONFIRM_DIFF=1` in the environment will show a unified diff and require confirmation before each write-back. Without an interactive TTY (or with `-n`), edit mode exits.
---
## Installation
```sh
make # full test suite, then build shim (run as a normal user)
doas make install # live prefix, default /usr/local
make install PREFIX=/usr # custom PREFIX (still elevated if under system paths)
make install DESTDIR=/tmp/pkg # staged install (no host post-install folded)
```
`make install` installs files only; it does not run the test suite (run `make` first). On a live install as root with empty `DESTDIR`, the Makefile tail-invokes `post-install` (broker user + staging `chown`). Otherwise run `make post-install` (or the shipped `post-install.sh`) after unpack / from `%post`, then merge `doas-snippet.conf` into `/etc/doas.conf`. See [packaging/README.md](packaging/README.md).
To build a shim without edit-mode support, use `make EDIT_MODE=0` and `make EDIT_MODE=0 install`. This omits `sudoedit`/`editas`, edit-mode code, and edit-broker artifacts; `sudo -e` still parses but exits with a feature-not-built error.
## Uninstall
```sh
make uninstall
```
See [packaging/README.md](packaging/README.md) for what is removed and how removal is validated.
---
## Testing
Main test entry points:
```sh
make check-src # test shim and broker from source; skips the final rebuild step a full `make` does
make # full test suite and shim build (run before privileged install)
```
For per-test details and docker images, see [tests/README.md](tests/README.md).
If the test suite cannot run in your environment, build with `make doasudo` and install files to match a normal `make install` layout (the shim expects `shim-utils.sh` under `$(PREFIX)/libexec/doasudo/`; with edit mode enabled, it also expects `edit-broker-client.sh`, the broker, and contracts beside it). When using `DESTDIR` for a staged install, run `make` (or `make check-src`) on a host similar to the deployment target first. See [packaging/README.md](packaging/README.md).
---
## Development
Design and architecture by [p-zubieta](https://github.com/p-zubieta). Parts of the codebase were written with the help of AI coding assistants. All changes were reviewed and tested by the maintainers.
---
## License
MIT