Commit 0d85d8f3 authored by Ariadne Conill's avatar Ariadne Conill 🐰
Browse files

main/doas: add support for configuration directories

ref tsc#1
parent 055b41da
# Maintainer: Drew DeVault <sir@cmpwn.com>
pkgname=doas
pkgver=6.8.1
pkgrel=3
pkgrel=4
pkgdesc="OpenBSD's temporary privilege escalation tool"
url="https://github.com/Duncaen/OpenDoas"
arch="all"
license="ISC"
makedepends="bison"
subpackages="$pkgname-doc"
source="$pkgname-$pkgver.tar.gz::https://github.com/Duncaen/OpenDoas/archive/v$pkgver.tar.gz"
install="$pkgname.post-install $pkgname.post-upgrade"
source="$pkgname-$pkgver.tar.gz::https://github.com/Duncaen/OpenDoas/archive/v$pkgver.tar.gz
configuration-directory.patch"
builddir="$srcdir/OpenDoas-$pkgver"
options="$options suid"
......@@ -20,7 +22,8 @@ build() {
./configure \
--prefix=/usr \
--without-pam \
--with-timestamp
--with-timestamp \
--with-doas-confdir
make
}
......@@ -31,14 +34,16 @@ check() {
package() {
make install DESTDIR="$pkgdir"
install -d "$pkgdir"/etc
cat > "$pkgdir"/etc/doas.conf <<-EOF
install -d "$pkgdir"/etc/examples
cat > "$pkgdir"/etc/examples/doas.conf <<-EOF
# see doas.conf(5) for configuration details
# Uncomment to allow group "wheel" to become root
# permit persist :wheel
EOF
chmod 600 "$pkgdir"/etc/doas.conf
}
sha512sums="d96fe1cdd70e9211de9996ad05bcf7a127facd02af48f7ab2561869d9d16708f1b61722c6e6b9fe15a62e9ef501e09b1ba444b7b43a066f1895e543ebc9402e7 doas-6.8.1.tar.gz"
sha512sums="
d96fe1cdd70e9211de9996ad05bcf7a127facd02af48f7ab2561869d9d16708f1b61722c6e6b9fe15a62e9ef501e09b1ba444b7b43a066f1895e543ebc9402e7 doas-6.8.1.tar.gz
79218c2798e67e6345818c357e651e09ef558d6cbcc5566e9e4816e8f4e73e4f737710caf617c211e89902ae7ef21cd520d3fc4d829550d40e1bd3b13befd0dc configuration-directory.patch
"
From 7de1d454bda06d68a04f4f2e48099398a7711ae9 Mon Sep 17 00:00:00 2001
From: Ariadne Conill <ariadne@dereferenced.org>
Date: Wed, 4 Aug 2021 04:47:04 -0600
Subject: [PATCH 1/8] add --with-confdir feature
This adds support for an /etc/doas.d configuration directory as discussed in #61. It is disabled by default.
---
README.md | 9 +++++++
configure | 8 +++++++
doas.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
parse.y | 3 ++-
4 files changed, 91 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index f15610c..f967eca 100644
--- a/README.md
+++ b/README.md
@@ -61,3 +61,12 @@ similar to sudo.
See the comment block in `timestamp.c` for an in-depth description on how
timestamps are created and checked to be as safe as possible.
+
+### `--with-doas-confdir`
+
+An optional feature can be enabled which will result in `doas` reading configuration
+snippets from `/etc/doas.d`. These configuration snippets have the same requirements
+as `/etc/doas.conf` (owned by root, not world-writable).
+
+If this feature is enabled, only the `/etc/doas.d` directory is read, and the historical
+`/etc/doas.conf` file is ignored.
\ No newline at end of file
diff --git a/configure b/configure
index 1f92f01..a3078dc 100755
--- a/configure
+++ b/configure
@@ -27,6 +27,7 @@ usage: configure [options]
--without-shadow disable shadow support
--with-timestamp enable timestamp support
+ --with-doas-confdir enable configuration directory support
--uid-max=NUM set UID_MAX (default 65535)
--gid-max=NUM set GID_MAX (default 65535)
@@ -38,6 +39,7 @@ EOF
# defaults
WITHOUT_TIMESTAMP=yes
+WITHOUT_CONFDIR=yes
UID_MAX=65535
GID_MAX=65535
@@ -56,6 +58,8 @@ for x; do
--target) TARGET=$var ;;
--enable-debug) DEBUG=yes ;;
--enable-static) BUILD_STATIC=yes ;;
+ --with-doas-confdir) WITHOUT_CONFDIR= ;;
+ --without-doas-confdir) WITHOUT_CONFDIR=yes ;;
--with-pam) WITHOUT_PAM=; WITHOUT_SHADOW=yes ;;
--with-shadow) WITHOUT_SHADOW=; WITHOUT_PAM=yes ;;
--without-pam) WITHOUT_PAM=yes ;;
@@ -558,4 +562,8 @@ fi
printf '#define DOAS_CONF "%s/doas.conf"\n' "${SYSCONFDIR}" >>$CONFIG_H
+if [ -z "$WITHOUT_CONFDIR" ]; then
+ printf '#define DOAS_CONFDIR "%s/doas.d"\n' "${SYSCONFDIR}" >>$CONFIG_H
+fi
+
printf '\n#endif /* CONFIG_H */\n' >>$CONFIG_H
diff --git a/doas.c b/doas.c
index ac3a42a..58701b7 100644
--- a/doas.c
+++ b/doas.c
@@ -35,6 +35,7 @@
#include <syslog.h>
#include <errno.h>
#include <fcntl.h>
+#include <dirent.h>
#include "openbsd.h"
#include "doas.h"
@@ -155,6 +156,7 @@ permit(uid_t uid, gid_t *groups, int ngroups, const struct rule **lastr,
static void
parseconfig(const char *filename, int checkperms)
{
+ extern const char *yyfn;
extern FILE *yyfp;
extern int yyparse(void);
struct stat sb;
@@ -164,6 +166,8 @@ parseconfig(const char *filename, int checkperms)
err(1, checkperms ? "doas is not enabled, %s" :
"could not open config file %s", filename);
+ yyfn = filename;
+
if (checkperms) {
if (fstat(fileno(yyfp), &sb) != 0)
err(1, "fstat(\"%s\")", filename);
@@ -174,11 +178,67 @@ parseconfig(const char *filename, int checkperms)
}
yyparse();
+ yyfn = NULL;
+
fclose(yyfp);
if (parse_errors)
exit(1);
}
+#ifdef DOAS_CONFDIR
+static int
+isconfdir(const char *dirpath)
+{
+ struct stat sb;
+
+ if (lstat(dirpath, &sb) != 0)
+ err(1, "lstat(\"%s\")", dirpath);
+
+ if ((sb.st_mode & (S_IFMT)) == S_IFDIR)
+ return 1;
+
+ errno = ENOTDIR;
+ return 0;
+}
+
+static void
+parseconfdir(const char *dirpath, int checkperms)
+{
+ struct dirent **dirent_table;
+ size_t i, dirent_count;
+ char pathbuf[PATH_MAX];
+
+ if (!isconfdir(dirpath))
+ err(1, checkperms ? "doas is not enabled, %s" :
+ "could not open config directory %s", dirpath);
+
+ dirent_count = scandir(dirpath, &dirent_table, NULL, alphasort);
+
+ for (i = 0; i < dirent_count; i++)
+ {
+ struct stat sb;
+ size_t pathlen;
+
+ pathlen = snprintf(pathbuf, sizeof pathbuf, "%s/%s", dirpath, dirent_table[i]->d_name);
+ free(dirent_table[i]);
+
+ /* make sure path ends in .conf */
+ if (strcmp(pathbuf + (pathlen - 5), ".conf"))
+ continue;
+
+ if (stat(pathbuf, &sb) != 0)
+ err(1, "stat(\"%s\")", pathbuf);
+
+ if ((sb.st_mode & (S_IFMT)) != S_IFREG)
+ continue;
+
+ parseconfig(pathbuf, checkperms);
+ }
+
+ free(dirent_table);
+}
+#endif
+
static void __dead
checkconfig(const char *confpath, int argc, char **argv,
uid_t uid, gid_t *groups, int ngroups, uid_t target)
@@ -188,7 +248,13 @@ checkconfig(const char *confpath, int argc, char **argv,
if (setresuid(uid, uid, uid) != 0)
err(1, "setresuid");
+#ifdef DOAS_CONFDIR
+ if (isconfdir(confpath))
+ parseconfdir(confpath, 0);
+ else
+#else
parseconfig(confpath, 0);
+#endif
if (!argc)
exit(0);
@@ -330,7 +396,13 @@ main(int argc, char **argv)
if (geteuid())
errx(1, "not installed setuid");
+#ifdef DOAS_CONFDIR
+ if (isconfdir(DOAS_CONFDIR))
+ parseconfdir(DOAS_CONFDIR, 1);
+ else
+#else
parseconfig(DOAS_CONF, 1);
+#endif
/* cmdline is used only for logging, no need to abort on truncate */
(void)strlcpy(cmdline, argv[0], sizeof(cmdline));
diff --git a/parse.y b/parse.y
index 388c2a5..c6d7ebf 100644
--- a/parse.y
+++ b/parse.y
@@ -49,6 +49,7 @@ typedef struct {
} yystype;
#define YYSTYPE yystype
+const char *yyfn;
FILE *yyfp;
struct rule **rules;
@@ -203,7 +204,7 @@ yyerror(const char *fmt, ...)
va_start(va, fmt);
vfprintf(stderr, fmt, va);
va_end(va);
- fprintf(stderr, " at line %d\n", yylval.lineno + 1);
+ fprintf(stderr, " at %s, line %d\n", yyfn, yylval.lineno + 1);
parse_errors++;
}
From 046ff34408ea8bf2cafc079bd71a126aa009b005 Mon Sep 17 00:00:00 2001
From: Ariadne Conill <ariadne@dereferenced.org>
Date: Wed, 4 Aug 2021 09:20:35 -0600
Subject: [PATCH 2/8] gracefully handle ENOENT in isconfdir()
---
doas.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/doas.c b/doas.c
index 58701b7..4c0cafe 100644
--- a/doas.c
+++ b/doas.c
@@ -191,8 +191,13 @@ isconfdir(const char *dirpath)
{
struct stat sb;
- if (lstat(dirpath, &sb) != 0)
- err(1, "lstat(\"%s\")", dirpath);
+ if (lstat(dirpath, &sb) != 0) {
+ if (errno != ENOENT)
+ err(1, "lstat(\"%s\")", dirpath);
+
+ errno = ENOTDIR;
+ return 0;
+ }
if ((sb.st_mode & (S_IFMT)) == S_IFDIR)
return 1;
From 6e76fb04ac637a1001ba201559f28279e3abe738 Mon Sep 17 00:00:00 2001
From: Ariadne Conill <ariadne@dereferenced.org>
Date: Wed, 4 Aug 2021 09:31:49 -0600
Subject: [PATCH 3/8] ensure pathlen - 5 is always non-zero
---
doas.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/doas.c b/doas.c
index 4c0cafe..f827fcd 100644
--- a/doas.c
+++ b/doas.c
@@ -228,6 +228,9 @@ parseconfdir(const char *dirpath, int checkperms)
free(dirent_table[i]);
/* make sure path ends in .conf */
+ if (pathlen < 6)
+ continue;
+
if (strcmp(pathbuf + (pathlen - 5), ".conf"))
continue;
From cac56ea61e16d0ccb91100164a61e9f7215604e5 Mon Sep 17 00:00:00 2001
From: Ariadne Conill <ariadne@dereferenced.org>
Date: Wed, 4 Aug 2021 10:17:35 -0600
Subject: [PATCH 4/8] bail if dirent_count < 0
---
doas.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/doas.c b/doas.c
index f827fcd..6e308c8 100644
--- a/doas.c
+++ b/doas.c
@@ -210,7 +210,7 @@ static void
parseconfdir(const char *dirpath, int checkperms)
{
struct dirent **dirent_table;
- size_t i, dirent_count;
+ int i, dirent_count;
char pathbuf[PATH_MAX];
if (!isconfdir(dirpath))
@@ -218,6 +218,9 @@ parseconfdir(const char *dirpath, int checkperms)
"could not open config directory %s", dirpath);
dirent_count = scandir(dirpath, &dirent_table, NULL, alphasort);
+ if (dirent_count < 0)
+ err(1, checkperms ? "doas is not enabled, %s" :
+ "could not open config directory %s", dirpath);
for (i = 0; i < dirent_count; i++)
{
From 8d224060adbdb1dececeb02660df8693f7c54a40 Mon Sep 17 00:00:00 2001
From: Ariadne Conill <ariadne@dereferenced.org>
Date: Wed, 4 Aug 2021 10:20:33 -0600
Subject: [PATCH 5/8] error out if no matching configuration files are found in
the configuration directory
---
doas.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/doas.c b/doas.c
index 6e308c8..cdfa3ea 100644
--- a/doas.c
+++ b/doas.c
@@ -210,7 +210,7 @@ static void
parseconfdir(const char *dirpath, int checkperms)
{
struct dirent **dirent_table;
- int i, dirent_count;
+ int i, m, dirent_count;
char pathbuf[PATH_MAX];
if (!isconfdir(dirpath))
@@ -222,7 +222,7 @@ parseconfdir(const char *dirpath, int checkperms)
err(1, checkperms ? "doas is not enabled, %s" :
"could not open config directory %s", dirpath);
- for (i = 0; i < dirent_count; i++)
+ for (i = 0, m = 0; i < dirent_count; i++)
{
struct stat sb;
size_t pathlen;
@@ -244,9 +244,16 @@ parseconfdir(const char *dirpath, int checkperms)
continue;
parseconfig(pathbuf, checkperms);
+ m++;
}
free(dirent_table);
+
+ if (!m) {
+ fprintf(stderr, "doas is not enabled, %s: no matching configuration files found\n",
+ dirpath);
+ exit(1);
+ }
}
#endif
From 35c3e69fa52157683b8ae6fe040367390aa63bb6 Mon Sep 17 00:00:00 2001
From: Ariadne Conill <ariadne@dereferenced.org>
Date: Wed, 4 Aug 2021 10:34:28 -0600
Subject: [PATCH 6/8] use errx instead of fprintf(stderr)
---
doas.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/doas.c b/doas.c
index cdfa3ea..b50138a 100644
--- a/doas.c
+++ b/doas.c
@@ -249,11 +249,8 @@ parseconfdir(const char *dirpath, int checkperms)
free(dirent_table);
- if (!m) {
- fprintf(stderr, "doas is not enabled, %s: no matching configuration files found\n",
- dirpath);
- exit(1);
- }
+ if (!m)
+ errx(1, "doas is not enabled, %s: no matching configuration files found\n", dirpath);
}
#endif
From c9ff0fcdc0253679a0348995c36f89edc8d73a5b Mon Sep 17 00:00:00 2001
From: Ariadne Conill <ariadne@dereferenced.org>
Date: Wed, 4 Aug 2021 16:50:58 -0600
Subject: [PATCH 7/8] fix up the ifndef DOAS_CONFDIR branch
---
doas.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/doas.c b/doas.c
index b50138a..d77186b 100644
--- a/doas.c
+++ b/doas.c
@@ -267,9 +267,8 @@ checkconfig(const char *confpath, int argc, char **argv,
if (isconfdir(confpath))
parseconfdir(confpath, 0);
else
-#else
- parseconfig(confpath, 0);
#endif
+ parseconfig(confpath, 0);
if (!argc)
exit(0);
@@ -415,9 +414,8 @@ main(int argc, char **argv)
if (isconfdir(DOAS_CONFDIR))
parseconfdir(DOAS_CONFDIR, 1);
else
-#else
- parseconfig(DOAS_CONF, 1);
#endif
+ parseconfig(DOAS_CONF, 1);
/* cmdline is used only for logging, no need to abort on truncate */
(void)strlcpy(cmdline, argv[0], sizeof(cmdline));
From 9fe4df5f004435fa0b092dc15a3c5ab09090f45d Mon Sep 17 00:00:00 2001
From: Ariadne Conill <ariadne@dereferenced.org>
Date: Fri, 3 Sep 2021 11:59:12 -0600
Subject: [PATCH 8/8] add manpage for doas.d(5)
---
GNUmakefile | 1 +
doas.conf.5 | 1 +
doas.d.5 | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 52 insertions(+)
create mode 100644 doas.d.5
diff --git a/GNUmakefile b/GNUmakefile
index 2eef88e..423731c 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -24,6 +24,7 @@ install: ${PROG} ${MAN}
chmod ${BINMODE} ${DESTDIR}${BINDIR}/${PROG}
cp -f doas.1 ${DESTDIR}${MANDIR}/man1
cp -f doas.conf.5 ${DESTDIR}${MANDIR}/man5
+ cp -f doas.d.5 ${DESTDIR}${MANDIR}/man5
uninstall:
rm -f ${DESTDIR}${BINDIR}/${PROG}
diff --git a/doas.conf.5 b/doas.conf.5
index e98bfbe..e90d512 100644
--- a/doas.conf.5
+++ b/doas.conf.5
@@ -143,6 +143,7 @@ permit nopass keepenv setenv { PATH } root as root
.Ed
.Sh SEE ALSO
.Xr doas 1 ,
+.Xr doas.d 5 ,
.Xr syslogd 8
.Sh HISTORY
The
diff --git a/doas.d.5 b/doas.d.5
new file mode 100644
index 0000000..8f5f96a
--- /dev/null
+++ b/doas.d.5
@@ -0,0 +1,50 @@
+.\"Copyright (c) 2021 Ariadne Conill <ariadne@dereferenced.org>
+.\"
+.\"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 $Mdocdate: October 9 2020 $
+.Dt DOAS.CONF 5
+.Os
+.Sh NAME
+.Nm doas.conf
+.Nd doas configuration file
+.Sh DESCRIPTION
+The
+.Xr doas 1
+utility executes commands as other users according to the rules
+configured in either the configuration file or, optionally, the
+configuration directory. The preference to use the configuration
+file or configuration directory is determined at compile time,
+.Xr doas 1
+will only consult one or the other.
+.Pp
+Configuration snippets stored in the configuration directory
+follow the same rules as the classic
+.Xr doas 1
+configuration file, documented in
+.Xr doas.conf 5 .
+They must end with the .conf extension, or they will be ignored.
+.Pp
+These snippets are read in alphabetical order and thus can be
+ordered in the same way as other configuration directories.
+.Sh FILES
+.Bl -tag -width /etc/doas.d -compact
+.It Pa /etc/doas.d
+.Xr doas 1
+configuration directory.
+.Sh SEE ALSO
+.Xr doas 1 ,
+.Xr doas.conf 5
+.Sh HISTORY
+The
+.Nm
+configuration directory first appeared in OpenDoas.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment