3 # Copyright (c) 2020 Kimmo Suominen <kim@netbsd.org>
5 # Permission to use, copy, modify, and distribute this software for any
6 # purpose with or without fee is hereby granted, provided that the above
7 # copyright notice and this permission notice appear in all copies.
9 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 # AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 # DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
14 # OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 # PERFORMANCE OF THIS SOFTWARE.
18 # Edit a temporary copy of the doas.conf file and check it for syntax
19 # errors before installing it as the actual doas.conf file.
23 PATH
=/bin
:/usr
/bin
:/usr
/local
/bin
35 echo "${PROG}: ${@}" 1>&2
41 echo "${PROG}: ${@}" 1>&2
61 if stat
--version >/dev
/null
2>&1
63 stat
-c '%U' "${file}"
65 stat
-f '%Su' "${file}"
67 |
awk '{print $1; exit}'
76 file_list
="${file_list} '${file}'"
78 if [ -n "${file_list}" ]
80 trap "rm -f ${file_list}" 0 1 2 15
87 Usage: ${PROG} [-n] [file]
90 Edit a temporary copy of a doas configuration file and check it for
91 syntax errors before installing it as the actual configuration file.
93 When no file is named, ${PROG} will edit the default configuration file
94 for doas(1): @DOAS_CONF@
98 -n Do not edit the file, just perform prerequisite checks. If this
99 switch is repeated, all output will be suppressed and the check
100 result is only indicated by the exit status.
110 n
) noop
=$
((${noop} + 1));;
111 *) usage
1>&2; exit 1;;
114 shift $
((${OPTIND} - 1))
118 1) DOAS_CONF
="${1}";;
119 *) usage
1>&2; exit 1;;
125 *) noop
=true
; exec >/dev
/null
2>&1;;
128 case "${DOAS_CONF}" in
130 warn
"Invalid filename: ${DOAS_CONF}"
131 die
"Try using './${DOAS_CONF}' instead"
135 doas_conf_dir
="$(dirname "${DOAS_CONF}")"
136 doas_conf_base
="$(basename "${DOAS_CONF}")"
137 DOAS_CONF
="${doas_conf_dir}/${doas_conf_base}"
138 doas_lock_file
="${DOAS_CONF}.lck"
140 # These checks are only for producing nicer diagnostic messages to the
141 # user. They are not relied on by the rest of the code.
143 if [ ! -e "${doas_conf_dir}" ]
145 die
"${doas_conf_dir} does not exist"
148 if [ ! -d "${doas_conf_dir}" ]
150 die
"${doas_conf_dir} is not a directory"
153 if [ ! -w "${doas_conf_dir}" ]
155 owner
="$(owner_of "${doas_conf_dir}")"
156 warn
"${doas_conf_dir} is not writable"
157 die
"You probably need to run ${PROG} as ${owner:-root}"
160 tmp_doas
="$(mktemp "${DOAS_CONF}.XXXXXXXXXX
")" \
161 || die
"You probably need to run ${PROG} as root"
162 set_trap_rm
"${tmp_doas}"
164 # It is important that the ln(1) command fails if the target already
165 # exists. Some versions are known to behave like "ln -f" by default
166 # (removing any existing target). Adjust PATH to avoid such ln(1)
169 tmp_test_ln
="$(mktemp "${DOAS_CONF}.XXXXXXXXXX
")"
170 set_trap_rm
"${tmp_doas}" "${tmp_test_ln}"
172 if ln "${tmp_doas}" "${tmp_test_ln}" 2>/dev
/null
174 die
'ln(1) is not safe for creating lock files, bailing'
177 # If a doas.conf file exists, copy it into the temporary file for
178 # editing. If none exist, the editor will open with an empty file.
180 if [ -f "${DOAS_CONF}" ]
182 if [ -r "${DOAS_CONF}" ]
184 cp "${DOAS_CONF}" "${tmp_doas}"
186 die
"${DOAS_CONF} is not readable"
192 if ! doas
-C "${DOAS_CONF}"
194 die
"${DOAS_CONF} contains syntax errors."
196 warn
'OK: Prerequisite checks passed'
200 # Link the temporary file to the lock file.
202 if ln "${tmp_doas}" "${doas_lock_file}"
204 set_trap_rm
"${tmp_doas}" "${tmp_test_ln}" "${doas_lock_file}"
206 die
"${DOAS_CONF} is already locked"
209 # Some versions of vi(1) exit with a code that reflects the number of
210 # editing errors made. This is why we ignore the exit code from the
213 "${EDITOR:-vi}" "${tmp_doas}" || true
215 while ! doas
-C "${tmp_doas}"
217 warn
"Press enter to edit doas.conf again to fix it,"
218 warn
"or interrupt ($(get_intr)) to cancel."
220 "${EDITOR:-vi}" "${tmp_doas}" || true
223 # Use mv(1) to rename the temporary file to doas.conf as it is atomic.
224 # Update: No longer use mv as it messes up permissions on the doas.conf file.
225 # Use install with ownership set to root.
227 if [ -s "${tmp_doas}" ]
229 if cmp -s "${tmp_doas}" "${DOAS_CONF}"
231 warn
"No changes made"
232 warn
"${DOAS_CONF} unchanged"
234 install -o root
-m "${doas_conf_mode}" \
235 "${tmp_doas}" "${DOAS_CONF}" \
236 && warn
"${DOAS_CONF} updated"
239 warn
"Not installing an empty doas.conf file"
240 warn
"${DOAS_CONF} unchanged"