mirror of
https://gitlab.alpinelinux.org/alpine/aports.git
synced 2025-05-12 14:34:20 +02:00
447 lines
13 KiB
Diff
447 lines
13 KiB
Diff
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.
|