summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LICENSE24
-rw-r--r--Makefile14
-rwxr-xr-xdoasedit68
-rw-r--r--doasedit.874
-rwxr-xr-xvidoas173
-rw-r--r--vidoas.878
6 files changed, 431 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..98e13b0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2017, Jesse Smith
+Copyright (c) 2022, Thomas Voss
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..9cd5b66
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,14 @@
+PREFIX = /usr/local
+DPREFIX = ${DESTDIR}${PREFIX}
+MANDIR = ${DPREFIX}/share/man
+DOAS_CONF = /etc/doas.conf
+
+all:
+
+install:
+ mkdir -p ${DPREFIX}/bin ${MANDIR}/man8
+ cp doasedit ${DPREFIX}/bin
+ cp doasedit.8 ${MANDIR}/man8
+ sed 's|@DOAS_CONF@|${DOAS_CONF}|g' vidoas >${DPREFIX}/bin/vidoas
+ sed 's|@DOAS_CONF@|${DOAS_CONF}|g' vidoas.8 >${MANDIR}/man8/vidoas.8
+ chmod +x ${DPREFIX}/bin/vidoas
diff --git a/doasedit b/doasedit
new file mode 100755
index 0000000..add6525
--- /dev/null
+++ b/doasedit
@@ -0,0 +1,68 @@
+#!/bin/sh
+
+# Copyright (c) 2022 Thomas Voss <mail@thomasvoss.com>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# Copy an existing text file to a temporary location. Then edit the file.
+# Attempt to then transfer the temporary file back to the original location if
+# the temprary file has been altered. Conclude with a little clean-up. Try to
+# avoid deleting any changes.
+
+warn() { echo "$PROG: $1" >&2; }
+die() { warn "$2"; exit $1; }
+
+get_intr() {
+ stty -a | sed -En '
+ /^(.* )?intr = / {
+ s///
+ s/;.*$//
+ p
+ }'
+}
+
+PROG=${0##*/}
+
+[ $# -ne 1 ] && {
+ echo "Usage: $PROG file"
+ exit 1
+}
+
+[ ! -f "$1" ] && die 2 "$1: File does not exist or is a special file/link."
+[ -L "$1" ] && die 2 "$1: File is a symbolic link, refusing to edit."
+[ ! -r "$1" ] && die 3 "$1: File cannot be read by the current user."
+
+tmp=$(mktemp --tmpdir doasedit.XXXXXXXX --suffix="${1//*./.}") || \
+ die 4 "Could not create temporary file."
+trap "rm -f $tmp" EXIT HUP INT TERM
+cp "$1" "$tmp" || die 5 "$1: Unable to copy file."
+
+"${VISUAL:-${EDITOR:-vi}}" "$tmp" || {
+ warn "Could not run visual editor '$VISUAL' or editor '$EDITOR'."
+ die 6 "Make sure the VISUAL and/or EDITOR variables are set."
+}
+
+cmp -s "$1" "$tmp" && \
+ die 0 "File unchanged. Not writing back to original location."
+
+# At this point the file has been changed. Make sure it still exists.
+[ -f "$tmp" ] && {
+ doas cp "$tmp" "$1"
+ until cmp -s "$tmp" "$1"; do
+ warn "$1: Copying failed. Press enter to try again,"
+ warn "or ($(get_intr)) to cancel."
+ read _
+ doas cp "$tmp" "$1"
+ done
+}
diff --git a/doasedit.8 b/doasedit.8
new file mode 100644
index 0000000..2d2908d
--- /dev/null
+++ b/doasedit.8
@@ -0,0 +1,74 @@
+.\"
+.\" Copyright (c) 2021 Jesse Smith <jessefrgsmith@yahoo.ca>
+.\" Copyright (c) 2022 Thomas Voss <mail@thomasvoss.com>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for
+.\" any purpose with or without fee is hereby granted, provided that
+.\" the above copyright notice and this permission notice appear in all
+.\" copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+.\" WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+.\" AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+.\" OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+.\" TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+.\" PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd November 14, 2022
+.Dt DOASEDIT 8
+.Os
+.Sh NAME
+.Nm doasedit
+.Nd edit a text file with root access as a non-root user
+.Sh SYNOPSIS
+.Nm
+.Ar file
+.Sh DESCRIPTION
+The
+.Nm
+utility opens an editor on a temporary copy of a text file.
+Once the file has been altered, it is written back to the original location,
+using doas for elevated access.
+This is intended for use in editing configuration files where the user may need
+to be root to edit a file, but does not wish to run their text editor as the
+super user.
+.Pp
+The doasedit utility accepts one argument, the file to be edited.
+The text editor used during the editing process is set using the VISUAL
+environment variable.
+If
+.Ev VISUAL
+is not set
+.Ev EDITOR
+is tried instead.
+If both environment variables are not set then
+.Xr vi(1)
+is used as a fallback.
+.Sh EXIT STATUS
+.Ex -std
+.Sh ENVIRONMENT
+.Bl -tag -width Ds
+.It Ev VISUAL
+The editor to use to edit the target text file.
+If the VISUAL variable is not set, then EDTIOR is used as a fallback.
+.It Ev EDITOR
+The editor to use to edit the target text file if VISUAL is not set.
+If the EDITOR variable is not set, then the command
+.Xr vi 1
+is used.
+.El
+.Sh SEE ALSO
+.Xr doas 1 ,
+.Xr vi 1 ,
+.Xr doas.conf 5 ,
+.Xr vidoas 8
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+utility and manual page were originally written by
+.An Jesse Smith Aq Mt jessefrgsmith@yahoo.ca ,
+but are now maintained by
+.An Thomas Voss Aq Mt mail@thomasvoss.com .
diff --git a/vidoas b/vidoas
new file mode 100755
index 0000000..bc01d63
--- /dev/null
+++ b/vidoas
@@ -0,0 +1,173 @@
+#!/bin/sh
+
+# Copyright (c) 2020 Kimmo Suominen <kim@netbsd.org>
+# Copyright (c) 2022 Thomas Voss <mail@thomasvoss.com>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# Edit a temporary copy of the doas.conf file and check it for syntax
+# errors before installing it as the actual doas.conf file.
+
+set -eu
+
+PATH=/bin:/usr/bin:/usr/local/bin
+export PATH
+
+PROG="${0##*/}"
+
+umask 022
+
+DOAS_CONF=@DOAS_CONF@
+doas_conf_mode="0600"
+
+warn() { echo "$PROG: $@" >&2; }
+die() { rv=$1; shift; warn "$@"; exit $rv; }
+
+get_intr() {
+ stty -a | sed -En '
+ /^(.* )?intr = / {
+ s///
+ s/;.*$//
+ p
+ }'
+}
+
+set_trap_rm() {
+ local file files
+ files=
+ for file in "$@"; do
+ files="$files '$file'"
+ done
+ [ -n "$files" ] && trap "rm -f $files" EXIT HUP INT TERM
+}
+
+noop=0
+
+while getopts hn c; do
+ case "$c" in
+ n)
+ noop=$(($noop + 1))
+ ;;
+ *)
+ echo "Usage: $PROG [-n] [file]" >&2;
+ exit 1
+ ;;
+ esac
+done
+shift $(($OPTIND - 1))
+
+case $# in
+0) ;;
+1) DOAS_CONF="$1" ;;
+*) usage 1>&2; exit 1 ;;
+esac
+
+case ${noop} in
+0) noop=false ;;
+1) noop=true ;;
+*) noop=true; exec >/dev/null 2>&1 ;;
+esac
+
+case "$DOAS_CONF" in
+-*)
+ warn "Invalid filename: $DOAS_CONF"
+ die 1 "Try using './$DOAS_CONF' instead"
+ ;;
+esac
+
+doas_conf_dir="$(dirname "$DOAS_CONF")"
+doas_conf_base="$(basename "$DOAS_CONF")"
+DOAS_CONF="$doas_conf_dir/$doas_conf_base"
+doas_lock_file="$DOAS_CONF.lck"
+
+# These checks are only for producing nicer diagnostic messages to the
+# user. They are not relied on by the rest of the code.
+
+[ ! -e "$doas_conf_dir" ] && die 1 "$doas_conf_dir does not exist"
+[ ! -d "$doas_conf_dir" ] && die 1 "$doas_conf_dir is not a directory"
+[ ! -w "$doas_conf_dir" ] && {
+ owner="$(stat -c %U "$doas_conf_dir")"
+ warn "$doas_conf_dir is not writable"
+ die 1 "You probably need to run $PROG as $owner"
+}
+
+tmp_doas="$(mktemp --tmpdir vidoas.XXXXXXXXXX)" \
+ || die 1 "You probably need to run $PROG as root"
+set_trap_rm "$tmp_doas"
+
+# It is important that the ln(1) command fails if the target already
+# exists. Some versions are known to behave like "ln -f" by default
+# (removing any existing target). Adjust PATH to avoid such ln(1)
+# implementations.
+
+tmp_test_ln="$(mktemp --tmpdir vidoas.XXXXXXXXXX)"
+set_trap_rm "$tmp_doas" "$tmp_test_ln"
+
+ln "$tmp_doas" "$tmp_test_ln" 2>/dev/null \
+ && die 1 'ln(1) is not safe for creating lock files, bailing'
+
+# If a doas.conf file exists, copy it into the temporary file for
+# editing. If none exist, the editor will open with an empty file.
+
+[ -f "$DOAS_CONF" ] && {
+ if [ -r "$DOAS_CONF" ]; then
+ cp "$DOAS_CONF" "$tmp_doas"
+ else
+ die 1 "$DOAS_CONF is not readable"
+ fi
+}
+
+$noop && {
+ doas -C "$DOAS_CONF" || die 1 "$DOAS_CONF contains syntax errors."
+ die 0 'OK: Prerequisite checks passed'
+}
+
+# Link the temporary file to the lock file.
+
+if ln "$tmp_doas" "$doas_lock_file"; then
+ set_trap_rm "$tmp_doas" "$tmp_test_ln" "$doas_lock_file"
+else
+ die 1 "$DOAS_CONF is already locked"
+fi
+
+# Some versions of vi(1) exit with a code that reflects the number of
+# editing errors made. This is why we ignore the exit code from the
+# editor.
+
+doasedit "$tmp_doas" || true
+
+until doas -C "$tmp_doas"; do
+ warn "Press enter to edit doas.conf again to fix it,"
+ warn "or ($(get_intr)) to cancel."
+ read _
+ doasedit "$tmp_doas" || true
+done
+
+# Use mv(1) to rename the temporary file to doas.conf as it is atomic.
+# Update: No longer use mv as it messes up permissions on the doas.conf file.
+# Use install with ownership set to root.
+
+if [ -s "$tmp_doas" ]; then
+ if cmp -s "$tmp_doas" "$DOAS_CONF"; then
+ warn "No changes made"
+ warn "$DOAS_CONF unchanged"
+ else
+ install -o root -m "$doas_conf_mode" "$tmp_doas" \
+ "$DOAS_CONF" \
+ && warn "$DOAS_CONF updated"
+ fi
+else
+ warn "Not installing an empty doas.conf file"
+ warn "$DOAS_CONF unchanged"
+fi
diff --git a/vidoas.8 b/vidoas.8
new file mode 100644
index 0000000..56a0734
--- /dev/null
+++ b/vidoas.8
@@ -0,0 +1,78 @@
+.\"
+.\" Copyright (c) 2020 Kimmo Suominen <kim@netbsd.org>
+.\" Copyright (c) 2022 Thomas Voss <mail@thomasvoss.com>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for
+.\" any purpose with or without fee is hereby granted, provided that
+.\" the above copyright notice and this permission notice appear in all
+.\" copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+.\" WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+.\" AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+.\" OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+.\" TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+.\" PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd November 14, 2022
+.Dt VIDOAS 8
+.Os
+.Sh NAME
+.Nm vidoas
+.Nd edit the doas configuration file
+.Sh SYNOPSIS
+.Nm
+.Op Fl n
+.Op Ar file
+.Sh DESCRIPTION
+The
+.Nm
+utility opens an editor on a temporary copy of the
+.Xr doas 1
+configuration file and checks it for syntax errors before installing it as the
+actual configuration file.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl n
+Do not edit the file, just perform prerequisite checks.
+If this switch is repeated, all output will be suppressed and the check result
+is only indicated by the exit status.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh ENVIRONMENT
+.Bl -tag -width Ds
+.It Ev VISUAL
+The editor to use to edit the target text file.
+If the VISUAL variable is not set, then EDTIOR is used as a fallback.
+.It Ev EDITOR
+The editor to use to edit the target text file if VISUAL is not set.
+If the EDITOR variable is not set, then the command
+.Xr vi 1
+is used.
+.El
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa @DOAS_CONF@
+The default configuration file to edit, when no
+.Ar file
+argument is specified.
+.El
+.Sh SEE ALSO
+.Xr doas 1 ,
+.Xr vi 1 ,
+.Xr doas.conf 5 ,
+.Xr doasedit 8
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+utility was originally written by
+.An Kimmo Suominen Aq Mt kim@netbsd.org
+and the manual page was originally written by
+.An Jesse Smith Aq Mt jessefrgsmith@yahoo.ca ,
+but both are now maintained by
+.An Thomas Voss Aq Mt mail@thomasvoss.com .