aboutsummaryrefslogtreecommitdiffstats
path: root/main/doas/configuration-directory.patch
diff options
context:
space:
mode:
Diffstat (limited to 'main/doas/configuration-directory.patch')
-rw-r--r--main/doas/configuration-directory.patch447
1 files changed, 447 insertions, 0 deletions
diff --git a/main/doas/configuration-directory.patch b/main/doas/configuration-directory.patch
new file mode 100644
index 00000000000..1ab9b968d1e
--- /dev/null
+++ b/main/doas/configuration-directory.patch
@@ -0,0 +1,447 @@
+Patch-Source: https://github.com/Duncaen/OpenDoas/pull/71 (rebased + one extra commit)
+--
+From a6aa77d9f4b9ad4556e478d6779dbebd4143a98a Mon Sep 17 00:00:00 2001
+From: Ariadne Conill <ariadne@dereferenced.org>
+Date: Wed, 4 Aug 2021 04:47:04 -0600
+Subject: [PATCH] add --with-confdir feature
+
+This adds support for an /etc/doas.d configuration directory as discussed in #61. It is disabled by default.
+
+diff --git a/GNUmakefile b/GNUmakefile
+index 9470202..22be971 100644
+--- a/GNUmakefile
++++ b/GNUmakefile
+@@ -27,6 +27,7 @@ install: ${PROG} ${PAM_DOAS} ${MAN}
+ [ -n "${PAM_DOAS}" ] && chmod 0644 ${DESTDIR}${PAMDIR}/doas || true
+ 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/README.md b/README.md
+index 20ef9f2..92acded 100644
+--- a/README.md
++++ b/README.md
+@@ -43,3 +43,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 1c5d989..22a078e 100755
+--- a/configure
++++ b/configure
+@@ -28,6 +28,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)
+@@ -39,6 +40,7 @@ EOF
+
+ # defaults
+ WITHOUT_TIMESTAMP=yes
++WITHOUT_CONFDIR=yes
+ UID_MAX=65535
+ GID_MAX=65535
+
+@@ -58,6 +60,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 ;;
+@@ -565,4 +569,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..d77186b 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,82 @@ 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) {
++ if (errno != ENOENT)
++ err(1, "lstat(\"%s\")", dirpath);
++
++ errno = ENOTDIR;
++ return 0;
++ }
++
++ 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;
++ int i, m, 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);
++ if (dirent_count < 0)
++ err(1, checkperms ? "doas is not enabled, %s" :
++ "could not open config directory %s", dirpath);
++
++ for (i = 0, m = 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 (pathlen < 6)
++ continue;
++
++ 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);
++ m++;
++ }
++
++ free(dirent_table);
++
++ if (!m)
++ errx(1, "doas is not enabled, %s: no matching configuration files found\n", dirpath);
++}
++#endif
++
+ static void __dead
+ checkconfig(const char *confpath, int argc, char **argv,
+ uid_t uid, gid_t *groups, int ngroups, uid_t target)
+@@ -188,6 +263,11 @@ 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
++#endif
+ parseconfig(confpath, 0);
+ if (!argc)
+ exit(0);
+@@ -330,6 +410,11 @@ main(int argc, char **argv)
+ if (geteuid())
+ errx(1, "not installed setuid");
+
++#ifdef DOAS_CONFDIR
++ if (isconfdir(DOAS_CONFDIR))
++ parseconfdir(DOAS_CONFDIR, 1);
++ else
++#endif
+ parseconfig(DOAS_CONF, 1);
+
+ /* cmdline is used only for logging, no need to abort on truncate */
+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..c5eaa72
+--- /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.D 5
++.Os
++.Sh NAME
++.Nm doas.d
++.Nd doas configuration directory
++.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.
+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 c871cf723cc4cc1045ffc7de380f5271b4c29acf Mon Sep 17 00:00:00 2001
+From: Jakub Jirutka <jakub@jirutka.cz>
+Date: Sat, 13 May 2023 22:38:23 +0200
+Subject: [PATCH 9/9] read both /etc/doas.conf and /etc/doas.d/*.conf if
+ confdir is enabled
+
+The current behaviour of the configuration directory was required by the
+upstream, but it doesn't conform to established conventions used by
+virtually all programs on Linux that support modular configuration, and
+what the users naturally expect. Also, when someone used to vanilla
+OpenDoas or doas on BSD comes to Alpine, the way they're used to
+configuring it (via /etc/doas.conf) will no work without notice! It
+has already caused some problems and confusion.
+
+The current behaviour is: if /etc/doas.d exists, there must be at least one
+*.conf file and /etc/doas.conf is *ignored*.
+
+Since it doesn't look like the upstream will ever merge this, better to
+fix this patch to work as it should from the beginning...
+
+This new behaviour: /etc/doas.conf must always exist (as in unpatched
+OpenDoas) and will be read first; if /etc/doas.d exists and there are any
+*.conf files, they will be loaded as well.
+---
+ README.md | 7 +++----
+ doas.c | 22 +++++-----------------
+ doas.d.5 | 14 +++++---------
+ 3 files changed, 13 insertions(+), 30 deletions(-)
+
+diff --git a/README.md b/README.md
+index 92acded..d5b2e72 100644
+--- a/README.md
++++ b/README.md
+@@ -48,7 +48,6 @@ timestamps are created and checked to be as safe as possible.
+
+ 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
++as `/etc/doas.conf` (owned by root, not world-writable). The main configuration file
++`/etc/doas.conf` is still required to exist and it is read before `/etc/doas.d`. It is
++not an error if `/etc/doas.d` does not exist or no matching files are found there.
+diff --git a/doas.c b/doas.c
+index d77186b..affbe39 100644
+--- a/doas.c
++++ b/doas.c
+@@ -210,19 +210,14 @@ static void
+ parseconfdir(const char *dirpath, int checkperms)
+ {
+ struct dirent **dirent_table;
+- int i, m, dirent_count;
++ int 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);
+ if (dirent_count < 0)
+- err(1, checkperms ? "doas is not enabled, %s" :
+- "could not open config directory %s", dirpath);
++ return;
+
+- for (i = 0, m = 0; i < dirent_count; i++)
++ for (i = 0; i < dirent_count; i++)
+ {
+ struct stat sb;
+ size_t pathlen;
+@@ -244,13 +239,9 @@ parseconfdir(const char *dirpath, int checkperms)
+ continue;
+
+ parseconfig(pathbuf, checkperms);
+- m++;
+ }
+
+ free(dirent_table);
+-
+- if (!m)
+- errx(1, "doas is not enabled, %s: no matching configuration files found\n", dirpath);
+ }
+ #endif
+
+@@ -263,12 +254,11 @@ checkconfig(const char *confpath, int argc, char **argv,
+ if (setresuid(uid, uid, uid) != 0)
+ err(1, "setresuid");
+
++ parseconfig(confpath, 0);
+ #ifdef DOAS_CONFDIR
+ if (isconfdir(confpath))
+ parseconfdir(confpath, 0);
+- else
+ #endif
+- parseconfig(confpath, 0);
+ if (!argc)
+ exit(0);
+
+@@ -410,13 +400,11 @@ main(int argc, char **argv)
+ if (geteuid())
+ errx(1, "not installed setuid");
+
++ parseconfig(DOAS_CONF, 1);
+ #ifdef DOAS_CONFDIR
+ if (isconfdir(DOAS_CONFDIR))
+ parseconfdir(DOAS_CONFDIR, 1);
+- else
+ #endif
+- parseconfig(DOAS_CONF, 1);
+-
+ /* cmdline is used only for logging, no need to abort on truncate */
+ (void)strlcpy(cmdline, argv[0], sizeof(cmdline));
+ for (i = 1; i < argc; i++) {
+diff --git a/doas.d.5 b/doas.d.5
+index c5eaa72..5911a12 100644
+--- a/doas.d.5
++++ b/doas.d.5
+@@ -21,14 +21,9 @@
+ 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
++configured in the configuration file and, optionally, the
++configuration directory. 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 .
+@@ -47,4 +42,5 @@ configuration directory.
+ .Sh HISTORY
+ The
+ .Nm
+-configuration directory first appeared in OpenDoas.
++configuration directory first appeared as a patch for doas on
++Alpine Linux and it is not supported in upstream OpenDoas.