diff options
-rw-r--r-- | LICENSE | 24 | ||||
-rw-r--r-- | Makefile | 14 | ||||
-rwxr-xr-x | doasedit | 68 | ||||
-rw-r--r-- | doasedit.8 | 74 | ||||
-rwxr-xr-x | vidoas | 173 | ||||
-rw-r--r-- | vidoas.8 | 78 |
6 files changed, 431 insertions, 0 deletions
@@ -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 . @@ -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 . |