tawasuyu

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1569Shell 203Rust 109Markdown 993728 Sutichaykuna

⎇ 8b1673d689b25a7854e74067da850d4a8f8a09ea recipes/configuration-directory.patch 447 siq'ikuna · 13.1 KB Ñawpa willay ch'uya

base-system: promover 17 esenciales a canónicas + repo firmado (713→730) fb6cb05aa · sergio ·

1Patch-Source: https://github.com/Duncaen/OpenDoas/pull/71 (rebased + one extra commit)
2--
3From a6aa77d9f4b9ad4556e478d6779dbebd4143a98a Mon Sep 17 00:00:00 2001
4From: Ariadne Conill <ariadne@dereferenced.org>
5Date: Wed, 4 Aug 2021 04:47:04 -0600
6Subject: [PATCH] add --with-confdir feature
7
8This adds support for an /etc/doas.d configuration directory as discussed in #61. It is disabled by default.
9
10diff --git a/GNUmakefile b/GNUmakefile
11index 9470202..22be971 100644
12--- a/GNUmakefile
13+++ b/GNUmakefile
14@@ -27,6 +27,7 @@ install: ${PROG} ${PAM_DOAS} ${MAN}
15 	[ -n "${PAM_DOAS}" ] && chmod 0644 ${DESTDIR}${PAMDIR}/doas || true
16 	cp -f doas.1 ${DESTDIR}${MANDIR}/man1
17 	cp -f doas.conf.5 ${DESTDIR}${MANDIR}/man5
18+	cp -f doas.d.5 ${DESTDIR}${MANDIR}/man5
19 
20 uninstall:
21 	rm -f ${DESTDIR}${BINDIR}/${PROG}
22diff --git a/README.md b/README.md
23index 20ef9f2..92acded 100644
24--- a/README.md
25+++ b/README.md
26@@ -43,3 +43,12 @@ similar to sudo.
27 
28 See the comment block in `timestamp.c` for an in-depth description on how
29 timestamps are created and checked to be as safe as possible.
30+
31+### `--with-doas-confdir`
32+
33+An optional feature can be enabled which will result in `doas` reading configuration
34+snippets from `/etc/doas.d`.  These configuration snippets have the same requirements
35+as `/etc/doas.conf` (owned by root, not world-writable).
36+
37+If this feature is enabled, only the `/etc/doas.d` directory is read, and the historical
38+`/etc/doas.conf` file is ignored.
39\ No newline at end of file
40diff --git a/configure b/configure
41index 1c5d989..22a078e 100755
42--- a/configure
43+++ b/configure
44@@ -28,6 +28,7 @@ usage: configure [options]
45   --without-shadow       disable shadow support
46 
47   --with-timestamp       enable timestamp support
48+  --with-doas-confdir    enable configuration directory support
49 
50   --uid-max=NUM          set UID_MAX (default 65535)
51   --gid-max=NUM          set GID_MAX (default 65535)
52@@ -39,6 +40,7 @@ EOF
53 
54 # defaults
55 WITHOUT_TIMESTAMP=yes
56+WITHOUT_CONFDIR=yes
57 UID_MAX=65535
58 GID_MAX=65535
59 
60@@ -58,6 +60,8 @@ for x; do
61 	--target) TARGET=$var ;;
62 	--enable-debug) DEBUG=yes ;;
63 	--enable-static) BUILD_STATIC=yes ;;
64+	--with-doas-confdir) WITHOUT_CONFDIR= ;;
65+	--without-doas-confdir) WITHOUT_CONFDIR=yes ;;
66 	--with-pam) WITHOUT_PAM=; WITHOUT_SHADOW=yes ;;
67 	--with-shadow) WITHOUT_SHADOW=; WITHOUT_PAM=yes ;;
68 	--without-pam) WITHOUT_PAM=yes ;;
69@@ -565,4 +569,8 @@ fi
70 
71 printf '#define DOAS_CONF "%s/doas.conf"\n' "${SYSCONFDIR}" >>$CONFIG_H
72 
73+if [ -z "$WITHOUT_CONFDIR" ]; then
74+	printf '#define DOAS_CONFDIR "%s/doas.d"\n' "${SYSCONFDIR}" >>$CONFIG_H
75+fi
76+
77 printf '\n#endif /* CONFIG_H */\n' >>$CONFIG_H
78diff --git a/doas.c b/doas.c
79index ac3a42a..d77186b 100644
80--- a/doas.c
81+++ b/doas.c
82@@ -35,6 +35,7 @@
83 #include <syslog.h>
84 #include <errno.h>
85 #include <fcntl.h>
86+#include <dirent.h>
87 
88 #include "openbsd.h"
89 #include "doas.h"
90@@ -155,6 +156,7 @@ permit(uid_t uid, gid_t *groups, int ngroups, const struct rule **lastr,
91 static void
92 parseconfig(const char *filename, int checkperms)
93 {
94+	extern const char *yyfn;
95 	extern FILE *yyfp;
96 	extern int yyparse(void);
97 	struct stat sb;
98@@ -164,6 +166,8 @@ parseconfig(const char *filename, int checkperms)
99 		err(1, checkperms ? "doas is not enabled, %s" :
100 		    "could not open config file %s", filename);
101 
102+	yyfn = filename;
103+
104 	if (checkperms) {
105 		if (fstat(fileno(yyfp), &sb) != 0)
106 			err(1, "fstat(\"%s\")", filename);
107@@ -174,11 +178,82 @@ parseconfig(const char *filename, int checkperms)
108 	}
109 
110 	yyparse();
111+	yyfn = NULL;
112+
113 	fclose(yyfp);
114 	if (parse_errors)
115 		exit(1);
116 }
117 
118+#ifdef DOAS_CONFDIR
119+static int
120+isconfdir(const char *dirpath)
121+{
122+	struct stat sb;
123+
124+	if (lstat(dirpath, &sb) != 0) {
125+		if (errno != ENOENT)
126+			err(1, "lstat(\"%s\")", dirpath);
127+
128+		errno = ENOTDIR;
129+		return 0;
130+	}
131+
132+	if ((sb.st_mode & (S_IFMT)) == S_IFDIR)
133+		return 1;
134+
135+	errno = ENOTDIR;
136+	return 0;
137+}
138+
139+static void
140+parseconfdir(const char *dirpath, int checkperms)
141+{
142+	struct dirent **dirent_table;
143+	int i, m, dirent_count;
144+	char pathbuf[PATH_MAX];
145+
146+	if (!isconfdir(dirpath))
147+		err(1, checkperms ? "doas is not enabled, %s" :
148+		    "could not open config directory %s", dirpath);
149+
150+	dirent_count = scandir(dirpath, &dirent_table, NULL, alphasort);
151+	if (dirent_count < 0)
152+		err(1, checkperms ? "doas is not enabled, %s" :
153+		    "could not open config directory %s", dirpath);
154+
155+	for (i = 0, m = 0; i < dirent_count; i++)
156+	{
157+		struct stat sb;
158+		size_t pathlen;
159+
160+		pathlen = snprintf(pathbuf, sizeof pathbuf, "%s/%s", dirpath, dirent_table[i]->d_name);
161+		free(dirent_table[i]);
162+
163+		/* make sure path ends in .conf */
164+		if (pathlen < 6)
165+			continue;
166+
167+		if (strcmp(pathbuf + (pathlen - 5), ".conf"))
168+			continue;
169+
170+		if (stat(pathbuf, &sb) != 0)
171+			err(1, "stat(\"%s\")", pathbuf);
172+
173+		if ((sb.st_mode & (S_IFMT)) != S_IFREG)
174+			continue;
175+
176+		parseconfig(pathbuf, checkperms);
177+		m++;
178+	}
179+
180+	free(dirent_table);
181+
182+	if (!m)
183+		errx(1, "doas is not enabled, %s: no matching configuration files found\n", dirpath);
184+}
185+#endif
186+
187 static void __dead
188 checkconfig(const char *confpath, int argc, char **argv,
189     uid_t uid, gid_t *groups, int ngroups, uid_t target)
190@@ -188,6 +263,11 @@ checkconfig(const char *confpath, int argc, char **argv,
191 	if (setresuid(uid, uid, uid) != 0)
192 		err(1, "setresuid");
193 
194+#ifdef DOAS_CONFDIR
195+	if (isconfdir(confpath))
196+		parseconfdir(confpath, 0);
197+	else
198+#endif
199 	parseconfig(confpath, 0);
200 	if (!argc)
201 		exit(0);
202@@ -330,6 +410,11 @@ main(int argc, char **argv)
203 	if (geteuid())
204 		errx(1, "not installed setuid");
205 
206+#ifdef DOAS_CONFDIR
207+	if (isconfdir(DOAS_CONFDIR))
208+		parseconfdir(DOAS_CONFDIR, 1);
209+	else
210+#endif
211 	parseconfig(DOAS_CONF, 1);
212 
213 	/* cmdline is used only for logging, no need to abort on truncate */
214diff --git a/doas.conf.5 b/doas.conf.5
215index e98bfbe..e90d512 100644
216--- a/doas.conf.5
217+++ b/doas.conf.5
218@@ -143,6 +143,7 @@ permit nopass keepenv setenv { PATH } root as root
219 .Ed
220 .Sh SEE ALSO
221 .Xr doas 1 ,
222+.Xr doas.d 5 ,
223 .Xr syslogd 8
224 .Sh HISTORY
225 The
226diff --git a/doas.d.5 b/doas.d.5
227new file mode 100644
228index 0000000..c5eaa72
229--- /dev/null
230+++ b/doas.d.5
231@@ -0,0 +1,50 @@
232+.\"Copyright (c) 2021 Ariadne Conill <ariadne@dereferenced.org>
233+.\"
234+.\"Permission to use, copy, modify, and distribute this software for any
235+.\"purpose with or without fee is hereby granted, provided that the above
236+.\"copyright notice and this permission notice appear in all copies.
237+.\"
238+.\"THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
239+.\"WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
240+.\"MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
241+.\"ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
242+.\"WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
243+.\"ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
244+.\"OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
245+.Dd $Mdocdate: October 9 2020 $
246+.Dt DOAS.D 5
247+.Os
248+.Sh NAME
249+.Nm doas.d
250+.Nd doas configuration directory
251+.Sh DESCRIPTION
252+The
253+.Xr doas 1
254+utility executes commands as other users according to the rules
255+configured in either the configuration file or, optionally, the
256+configuration directory.  The preference to use the configuration
257+file or configuration directory is determined at compile time,
258+.Xr doas 1
259+will only consult one or the other.
260+.Pp
261+Configuration snippets stored in the configuration directory
262+follow the same rules as the classic
263+.Xr doas 1
264+configuration file, documented in
265+.Xr doas.conf 5 .
266+They must end with the .conf extension, or they will be ignored.
267+.Pp
268+These snippets are read in alphabetical order and thus can be
269+ordered in the same way as other configuration directories.
270+.Sh FILES
271+.Bl -tag -width /etc/doas.d -compact
272+.It Pa /etc/doas.d
273+.Xr doas 1
274+configuration directory.
275+.Sh SEE ALSO
276+.Xr doas 1 ,
277+.Xr doas.conf 5
278+.Sh HISTORY
279+The
280+.Nm
281+configuration directory first appeared in OpenDoas.
282diff --git a/parse.y b/parse.y
283index 388c2a5..c6d7ebf 100644
284--- a/parse.y
285+++ b/parse.y
286@@ -49,6 +49,7 @@ typedef struct {
287 } yystype;
288 #define YYSTYPE yystype
289 
290+const char *yyfn;
291 FILE *yyfp;
292 
293 struct rule **rules;
294@@ -203,7 +204,7 @@ yyerror(const char *fmt, ...)
295 	va_start(va, fmt);
296 	vfprintf(stderr, fmt, va);
297 	va_end(va);
298-	fprintf(stderr, " at line %d\n", yylval.lineno + 1);
299+	fprintf(stderr, " at %s, line %d\n", yyfn, yylval.lineno + 1);
300 	parse_errors++;
301 }
302 
303--
304From c871cf723cc4cc1045ffc7de380f5271b4c29acf Mon Sep 17 00:00:00 2001
305From: Jakub Jirutka <jakub@jirutka.cz>
306Date: Sat, 13 May 2023 22:38:23 +0200
307Subject: [PATCH 9/9] read both /etc/doas.conf and /etc/doas.d/*.conf if
308 confdir is enabled
309
310The current behaviour of the configuration directory was required by the
311upstream, but it doesn't conform to established conventions used by
312virtually all programs on Linux that support modular configuration, and
313what the users naturally expect. Also, when someone used to vanilla
314OpenDoas or doas on BSD comes to Alpine, the way they're used to
315configuring it (via /etc/doas.conf) will no work without notice! It
316has already caused some problems and confusion.
317
318The current behaviour is: if /etc/doas.d exists, there must be at least one
319*.conf file and /etc/doas.conf is *ignored*.
320
321Since it doesn't look like the upstream will ever merge this, better to
322fix this patch to work as it should from the beginning...
323
324This new behaviour: /etc/doas.conf must always exist (as in unpatched
325OpenDoas) and will be read first; if /etc/doas.d exists and there are any
326*.conf files, they will be loaded as well.
327---
328 README.md |  7 +++----
329 doas.c    | 22 +++++-----------------
330 doas.d.5  | 14 +++++---------
331 3 files changed, 13 insertions(+), 30 deletions(-)
332
333diff --git a/README.md b/README.md
334index 92acded..d5b2e72 100644
335--- a/README.md
336+++ b/README.md
337@@ -48,7 +48,6 @@ timestamps are created and checked to be as safe as possible.
338 
339 An optional feature can be enabled which will result in `doas` reading configuration
340 snippets from `/etc/doas.d`.  These configuration snippets have the same requirements
341-as `/etc/doas.conf` (owned by root, not world-writable).
342-
343-If this feature is enabled, only the `/etc/doas.d` directory is read, and the historical
344-`/etc/doas.conf` file is ignored.
345\ No newline at end of file
346+as `/etc/doas.conf` (owned by root, not world-writable).  The main configuration file
347+`/etc/doas.conf` is still required to exist and it is read before `/etc/doas.d`.  It is
348+not an error if `/etc/doas.d` does not exist or no matching files are found there.
349diff --git a/doas.c b/doas.c
350index d77186b..affbe39 100644
351--- a/doas.c
352+++ b/doas.c
353@@ -210,19 +210,14 @@ static void
354 parseconfdir(const char *dirpath, int checkperms)
355 {
356 	struct dirent **dirent_table;
357-	int i, m, dirent_count;
358+	int i, dirent_count;
359 	char pathbuf[PATH_MAX];
360 
361-	if (!isconfdir(dirpath))
362-		err(1, checkperms ? "doas is not enabled, %s" :
363-		    "could not open config directory %s", dirpath);
364-
365 	dirent_count = scandir(dirpath, &dirent_table, NULL, alphasort);
366 	if (dirent_count < 0)
367-		err(1, checkperms ? "doas is not enabled, %s" :
368-		    "could not open config directory %s", dirpath);
369+		return;
370 
371-	for (i = 0, m = 0; i < dirent_count; i++)
372+	for (i = 0; i < dirent_count; i++)
373 	{
374 		struct stat sb;
375 		size_t pathlen;
376@@ -244,13 +239,9 @@ parseconfdir(const char *dirpath, int checkperms)
377 			continue;
378 
379 		parseconfig(pathbuf, checkperms);
380-		m++;
381 	}
382 
383 	free(dirent_table);
384-
385-	if (!m)
386-		errx(1, "doas is not enabled, %s: no matching configuration files found\n", dirpath);
387 }
388 #endif
389 
390@@ -263,12 +254,11 @@ checkconfig(const char *confpath, int argc, char **argv,
391 	if (setresuid(uid, uid, uid) != 0)
392 		err(1, "setresuid");
393 
394+	parseconfig(confpath, 0);
395 #ifdef DOAS_CONFDIR
396 	if (isconfdir(confpath))
397 		parseconfdir(confpath, 0);
398-	else
399 #endif
400-	parseconfig(confpath, 0);
401 	if (!argc)
402 		exit(0);
403 
404@@ -410,13 +400,11 @@ main(int argc, char **argv)
405 	if (geteuid())
406 		errx(1, "not installed setuid");
407 
408+	parseconfig(DOAS_CONF, 1);
409 #ifdef DOAS_CONFDIR
410 	if (isconfdir(DOAS_CONFDIR))
411 		parseconfdir(DOAS_CONFDIR, 1);
412-	else
413 #endif
414-	parseconfig(DOAS_CONF, 1);
415-
416 	/* cmdline is used only for logging, no need to abort on truncate */
417 	(void)strlcpy(cmdline, argv[0], sizeof(cmdline));
418 	for (i = 1; i < argc; i++) {
419diff --git a/doas.d.5 b/doas.d.5
420index c5eaa72..5911a12 100644
421--- a/doas.d.5
422+++ b/doas.d.5
423@@ -21,14 +21,9 @@
424 The
425 .Xr doas 1
426 utility executes commands as other users according to the rules
427-configured in either the configuration file or, optionally, the
428-configuration directory.  The preference to use the configuration
429-file or configuration directory is determined at compile time,
430-.Xr doas 1
431-will only consult one or the other.
432-.Pp
433-Configuration snippets stored in the configuration directory
434-follow the same rules as the classic
435+configured in the configuration file and, optionally, the
436+configuration directory.  Configuration snippets stored in the
437+configuration directory follow the same rules as the classic
438 .Xr doas 1
439 configuration file, documented in
440 .Xr doas.conf 5 .
441@@ -47,4 +42,5 @@ configuration directory.
442 .Sh HISTORY
443 The
444 .Nm
445-configuration directory first appeared in OpenDoas.
446+configuration directory first appeared as a patch for doas on
447+Alpine Linux and it is not supported in upstream OpenDoas.