├── .editorconfig ├── .gitattributes ├── .gitignore ├── LICENSE ├── Makefile ├── README.adoc ├── sudo └── sudo.1.adoc /.editorconfig: -------------------------------------------------------------------------------- 1 | ; http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 4 8 | indent_style = tab 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.adoc] 13 | indent_size = 2 14 | indent_style = space 15 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | Makefile -linguist-detectable 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.[0-9] 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The ISC License 2 | 3 | Copyright (c) 2021-present Jakub Jirutka . 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any purpose 6 | with or without fee is hereby granted, provided that the above copyright notice 7 | and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 10 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 11 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 12 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 13 | OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 14 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 15 | THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SCRIPT_NAME := sudo 2 | 3 | prefix := $(or $(prefix),$(PREFIX),/usr/local) 4 | bindir := $(prefix)/bin 5 | mandir := $(prefix)/share/man 6 | 7 | ASCIIDOCTOR := asciidoctor 8 | INSTALL := install 9 | GIT := git 10 | SED := sed 11 | 12 | MAKEFILE_PATH = $(lastword $(MAKEFILE_LIST)) 13 | 14 | 15 | #: Print list of targets. 16 | help: 17 | @printf '%s\n\n' 'List of targets:' 18 | @$(SED) -En '/^#:.*/{ N; s/^#: (.*)\n([A-Za-z0-9_-]+).*/\2 \1/p }' $(MAKEFILE_PATH) \ 19 | | while read label desc; do printf '%-15s %s\n' "$$label" "$$desc"; done 20 | 21 | #: Install the script and man page into $DESTDIR/$prefix. 22 | install: install-exec install-man 23 | 24 | #: Install the script into $DESTDIR/$bindir. 25 | install-exec: 26 | mkdir -p $(DESTDIR)$(bindir) 27 | install -m 755 $(SCRIPT_NAME) $(DESTDIR)$(bindir)/$(SCRIPT_NAME) 28 | 29 | #: Install the man page into $DESTDIR/$mandir/man1. 30 | install-man: $(SCRIPT_NAME).1 31 | mkdir -p $(DESTDIR)$(mandir)/man1 32 | install -m 644 $(SCRIPT_NAME).1 $(DESTDIR)$(mandir)/man1/$(SCRIPT_NAME).1 33 | 34 | #: Generate a man page (requires asciidoctor). 35 | man: $(SCRIPT_NAME).1 36 | 37 | #: Uninstall the script from $DESTDIR. 38 | uninstall: 39 | rm -f "$(DESTDIR)$(bindir)/$(SCRIPT_NAME)" 40 | rm -f "$(DESTDIR)$(mandir)/man1/$(SCRIPT_NAME).1" 41 | 42 | #: Update version in README.adoc to $VERSION. 43 | bump-version: 44 | test -n "$(VERSION)" # $$VERSION 45 | $(SED) -E -i "s/^(:version:).*/\1 $(VERSION)/" README.adoc 46 | 47 | #: Bump version to $VERSION, create release commit and tag. 48 | release: .check-git-clean | bump-version 49 | test -n "$(VERSION)" # $$VERSION 50 | $(GIT) add . 51 | $(GIT) commit -m "Release version $(VERSION)" 52 | $(GIT) tag -s v$(VERSION) -m v$(VERSION) 53 | 54 | 55 | # Convert a man page. 56 | $(SCRIPT_NAME).1: $(SCRIPT_NAME).1.adoc 57 | $(ASCIIDOCTOR) -b manpage $(SCRIPT_NAME).1.adoc 58 | 59 | # Target for compatibility with GNU convention. 60 | install-data: install-man 61 | 62 | .check-git-clean: 63 | @test -z "$(shell $(GIT) status --porcelain)" \ 64 | || { echo 'You have uncommitted changes!' >&2; exit 1; } 65 | 66 | .PHONY: help install install-exec install-man man uninstall bump-version \ 67 | release .check-git-clean 68 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = doas sudo shim 2 | :proj-name: doas-sudo-shim 3 | :gh-name: jirutka/{proj-name} 4 | :version: 0.1.2 5 | 6 | This is a shim for the `sudo` command that utilizes https://www.mankier.com/1/doas[doas]. 7 | It supports only a subset of the `sudo` options (both short and long variants) that have an equivalent in `doas`, plus option `-i` (`--login`). 8 | 9 | 10 | == Requirements 11 | 12 | * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html[POSIX-sh] compatible shell (e.g. Busybox ash, dash, ZSH, bash, …) 13 | * `awk`, `cat`, `getopt` (BSD, Busybox or GNU) 14 | * `doas` (https://github.com/Duncaen/OpenDoas[OpenDoas] or from OpenBSD) 15 | * (https://github.com/asciidoctor/asciidoctor[Asciidoctor] to build a man page) 16 | 17 | 18 | == Installation 19 | 20 | === On Alpine Linux 21 | 22 | Install package https://pkgs.alpinelinux.org/packages?name={proj-name}[{proj-name}] from the Alpine’s Edge repository: 23 | 24 | [source, sh, subs="+attributes"] 25 | apk add {proj-name} 26 | 27 | 28 | === On Arch Linux 29 | 30 | Install package https://aur.archlinux.org/packages/{proj-name}[{proj-name}] from AUR: 31 | 32 | [source, sh, subs="+attributes"] 33 | yay -S {proj-name} 34 | 35 | Or use another AUR helper. 36 | 37 | 38 | === From Tarball 39 | 40 | [source, sh, subs="+attributes"] 41 | wget https://github.com/{gh-name}/archive/v{version}/{proj-name}-{version}.tar.gz 42 | tar -xzf {proj-name}-{version}.tar.gz 43 | cd {proj-name}-{version} 44 | make install DESTDIR=/ PREFIX=/usr/local 45 | 46 | ...or just download the link:https://raw.githubusercontent.com/{gh-name}/v{version}/sudo[sudo] script directly. 47 | 48 | 49 | == Usage 50 | 51 | Read man page link:sudo.1.adoc[sudo(1)]. 52 | 53 | 54 | == See Also 55 | 56 | * https://www.mankier.com/1/doas[doas(1)] 57 | * https://www.mankier.com/8/sudo[sudo(8)] 58 | 59 | 60 | == License 61 | 62 | This project is licensed under http://opensource.org/licenses/ISC/[ISC License]. 63 | For the full text of the license, see the link:LICENSE[LICENSE] file. 64 | -------------------------------------------------------------------------------- /sudo: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -u 3 | 4 | help() { 5 | cat <<-EOF 6 | Usage: 7 | sudo (-i | -s) [-n] [-u ] [ [--] [...]] 8 | sudo [-ins] [-u ] [--] [...] 9 | sudo [-h] 10 | 11 | Execute a command as another user using doas(1). 12 | 13 | This is not the original sudo, but the doas shim for sudo. It supports only 14 | a subset of the sudo options (both short and long) that have an equivalent in 15 | doas, plus option -i (--login). Refer to sudo(1) for more information. 16 | 17 | Please report bugs at . 18 | EOF 19 | } 20 | 21 | if [ $# -eq 0 ]; then 22 | help >&2 23 | exit 1 24 | fi 25 | 26 | # Note: "+" disables optional option parameters 27 | opts=$(getopt -n sudo -o +insu:h -l login,non-interactive,shell,user:,help -- "$@") || { 28 | help >&2 29 | exit 1 30 | } 31 | eval set -- "$opts" 32 | 33 | flag_i= 34 | flag_n= 35 | flag_s= 36 | user= 37 | while [ $# -gt 0 ]; do 38 | case "$1" in 39 | -i | --login) flag_i='-i';; 40 | -n | --non-interactive) flag_n='-n';; 41 | -s | --shell) flag_s='-s';; 42 | -u | --user) user=${2#\#}; shift;; 43 | -h | --help) help; exit 0;; 44 | --) shift; break;; 45 | esac 46 | shift 47 | done 48 | 49 | if [ "$flag_i" ] && [ "$flag_s" ]; then 50 | echo "sudo: you may not specify both the '-i' and '-s' options" >&2 51 | exit 1 52 | fi 53 | 54 | _doas() { 55 | exec doas $flag_n ${user:+-u "$user"} "$@" 56 | } 57 | 58 | user_shell() { 59 | if command -v getent >/dev/null 2>&1; then 60 | getent passwd "${user:-root}" | awk -F: 'END {print $NF ? $NF : "sh"}' 61 | else 62 | awk -F: '$1 == "'${user:-root}'" {print $NF; m=1} END {if (!m) print "sh"}' /etc/passwd 63 | fi 64 | } 65 | 66 | export SUDO_GID=$(id -g) 67 | export SUDO_UID=$(id -u) 68 | export SUDO_USER=$(id -un) 69 | 70 | if [ $# -eq 0 ]; then 71 | if [ "$flag_i" ]; then 72 | _doas -- "$(user_shell)" -c 'cd "$HOME"; exec "$0" -l' 73 | else 74 | _doas $flag_s 75 | fi 76 | elif [ "$flag_i" ]; then 77 | _doas -- "$(user_shell)" -l -c 'cd "$HOME"; "$0" "$@"' "$@" 78 | elif [ "$flag_s" ]; then 79 | _doas -- "${SHELL:-$(user_shell)}" -c '"$0" "$@"' "$@" 80 | else 81 | _doas -- "$@" 82 | fi 83 | -------------------------------------------------------------------------------- /sudo.1.adoc: -------------------------------------------------------------------------------- 1 | = sudo(1) 2 | :doctype: manpage 3 | :repo-uri: https://github.com/jirutka/doas-sudo-shim 4 | :issues-uri: {repo-uri}/issues 5 | ifdef::backend-manpage[] 6 | :doas: pass:q[*doas(1)*] 7 | :doas-conf: pass:q[*doas.conf(5)*] 8 | :sudo: pass:q[*sudo(8)*] 9 | endif::[] 10 | ifndef::backend-manpage[] 11 | :doas: https://www.mankier.com/1/doas[doas(1)] 12 | :doas-conf: https://www.mankier.com/5/doas.conf[doas.conf(5)] 13 | :sudo: https://www.mankier.com/8/sudo[sudo(8)] 14 | endif::[] 15 | 16 | 17 | == NAME 18 | 19 | sudo - execute a command as another user using doas 20 | 21 | 22 | == SYNOPSIS 23 | 24 | *sudo* (-i | -s) [-n] [-u <__user__>] [<__command__> [--] [<__args__>...]] + 25 | *sudo* [-ins] [-u <__user__>] <__command__> [--] [<__args__>...] + 26 | *sudo* [-h] 27 | 28 | 29 | == DESCRIPTION 30 | 31 | This is not the original {sudo}, but a shim for the `sudo` command that utilizes {doas}. 32 | It supports only a subset of the {sudo} options (both short and long variants) that have an equivalent in {doas}, plus option *-i* (*--login*). 33 | 34 | See {doas} and {sudo} for more information. 35 | 36 | 37 | == OPTIONS 38 | 39 | *-i*, *--login*:: 40 | Run the shell specified by the target __user__`'s password database entry as a login shell. 41 | This means that login-specific resource files such as `.profile`, `.bash_profile` or `.login` will be read by the shell. 42 | If a _command_ is specified, it is passed to the shell for execution via the shell`'s *-c* option. 43 | If no _command_ is specified, an interactive shell is executed. 44 | This shim attempts to change to that __user__`'s home directory right after running the shell. 45 | 46 | *-n*, *--non-interactive*:: 47 | Non interactive mode, fail if the matching rule doesn`'t have the `nopass` option. 48 | 49 | *-s*, *--shell*:: 50 | Run the shell specified by the `SHELL` environment variable if it is set or the shell specified by the invoking user`'s password database entry. 51 | If a command is specified, it is passed to the shell for execution via the shell`'s *-c* option. 52 | If no command is specified, an interactive shell is executed. 53 | Note that most shells behave differently when a command is specified as compared to an interactive session; consult the shell`'s manual for details. 54 | 55 | *-u* <__user__>, *--user* <__user__>:: 56 | Run the _command_ as a _user_, other than the default target user (usually `root`). 57 | The user may be either a user name or a numeric user-ID (UID). 58 | Unlike in the original {sudo}, numeric UIDs does not have to be prefixed with the '`#`' character and only UIDs listed in the password database are allowed. 59 | 60 | *-h*, *--help*:: 61 | Print help message and exit. 62 | 63 | 64 | == FILES 65 | 66 | Refer to {doas}. 67 | 68 | 69 | == ENVIRONMENT 70 | 71 | This shim sets the following environment variables for compatibility with {sudo}. 72 | However, they must be explicitly allowed in {doas-conf} (using `setenv` or `keepenv`) to be exported into the created environment. 73 | 74 | *SUDO_GID*:: 75 | Set to the group-ID of the user who invoked *sudo*. 76 | 77 | *SUDO_UID*:: 78 | Set to the user-ID of the user who invoked *sudo*. 79 | 80 | *SUDO_USER*:: 81 | Set to the login name of the user who invoked *sudo*. 82 | 83 | Refer to {doas} for more information. 84 | 85 | 86 | == EXIT CODES 87 | 88 | Refer to {doas}. 89 | 90 | 91 | == AUTHORS 92 | 93 | Jakub Jirutka 94 | 95 | 96 | == REPORTING BUGS 97 | 98 | Report bugs to the project`'s issue tracker at {issues-uri}. 99 | 100 | 101 | == SEE ALSO 102 | 103 | {doas} 104 | {doas-conf} 105 | {sudo} 106 | --------------------------------------------------------------------------------