Skip to content

Commit 1157d84

Browse files
committed
add --with-confdir feature
This adds support for an /etc/doas.d configuration directory as discussed in #61. It is disabled by default.
1 parent 9a25a6d commit 1157d84

File tree

5 files changed

+95
-3
lines changed

5 files changed

+95
-3
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,12 @@ similar to sudo.
6161

6262
See the comment block in `timestamp.c` for an in-depth description on how
6363
timestamps are created and checked to be as safe as possible.
64+
65+
### `--with-doas-confdir`
66+
67+
An optional feature can be enabled which will result in `doas` reading configuration
68+
snippets from `/etc/doas.d`. These configuration snippets have the same requirements
69+
as `/etc/doas.conf` (owned by root, not world-writable).
70+
71+
If this feature is enabled, only the `/etc/doas.d` directory is read, and the historical
72+
`/etc/doas.conf` file is ignored.

configure

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ usage: configure [options]
2727
--without-shadow disable shadow support
2828
2929
--with-timestamp enable timestamp support
30+
--with-doas-confdir enable configuration directory support
3031
3132
--uid-max=NUM set UID_MAX (default 65535)
3233
--gid-max=NUM set GID_MAX (default 65535)
@@ -38,6 +39,7 @@ EOF
3839

3940
# defaults
4041
WITHOUT_TIMESTAMP=yes
42+
WITHOUT_CONFDIR=yes
4143
UID_MAX=65535
4244
GID_MAX=65535
4345

@@ -56,6 +58,8 @@ for x; do
5658
--target) TARGET=$var ;;
5759
--enable-debug) DEBUG=yes ;;
5860
--enable-static) BUILD_STATIC=yes ;;
61+
--with-doas-confdir) WITHOUT_CONFDIR= ;;
62+
--without-doas-confdir) WITHOUT_CONFDIR=yes ;;
5963
--with-pam) WITHOUT_PAM=; WITHOUT_SHADOW=yes ;;
6064
--with-shadow) WITHOUT_SHADOW=; WITHOUT_PAM=yes ;;
6165
--without-pam) WITHOUT_PAM=yes ;;
@@ -558,4 +562,8 @@ fi
558562

559563
printf '#define DOAS_CONF "%s/doas.conf"\n' "${SYSCONFDIR}" >>$CONFIG_H
560564

565+
if [ -z "$WITHOUT_CONFDIR" ]; then
566+
printf '#define DOAS_CONFDIR "%s/doas.d"\n' "${SYSCONFDIR}" >>$CONFIG_H
567+
fi
568+
561569
printf '\n#endif /* CONFIG_H */\n' >>$CONFIG_H

doas.c

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <syslog.h>
3636
#include <errno.h>
3737
#include <fcntl.h>
38+
#include <dirent.h>
3839

3940
#include "openbsd.h"
4041
#include "doas.h"
@@ -155,15 +156,15 @@ permit(uid_t uid, gid_t *groups, int ngroups, const struct rule **lastr,
155156
static void
156157
parseconfig(const char *filename, int checkperms)
157158
{
158-
extern FILE *yyfp;
159-
extern int yyparse(void);
160159
struct stat sb;
161160

162161
yyfp = fopen(filename, "r");
163162
if (!yyfp)
164163
err(1, checkperms ? "doas is not enabled, %s" :
165164
"could not open config file %s", filename);
166165

166+
yyfn = filename;
167+
167168
if (checkperms) {
168169
if (fstat(fileno(yyfp), &sb) != 0)
169170
err(1, "fstat(\"%s\")", filename);
@@ -174,11 +175,67 @@ parseconfig(const char *filename, int checkperms)
174175
}
175176

176177
yyparse();
178+
yyfn = NULL;
179+
177180
fclose(yyfp);
178181
if (parse_errors)
179182
exit(1);
180183
}
181184

185+
#ifdef DOAS_CONFDIR
186+
static int
187+
isconfdir(const char *dirpath)
188+
{
189+
struct stat sb;
190+
191+
if (lstat(dirpath, &sb) != 0)
192+
err(1, "lstat(\"%s\")", dirpath);
193+
194+
if ((sb.st_mode & (S_IFMT)) == S_IFDIR)
195+
return 1;
196+
197+
errno = ENOTDIR;
198+
return 0;
199+
}
200+
201+
static void
202+
parseconfdir(const char *dirpath, int checkperms)
203+
{
204+
struct dirent **dirent_table;
205+
size_t i, dirent_count;
206+
char pathbuf[PATH_MAX];
207+
208+
if (!isconfdir(dirpath))
209+
err(1, checkperms ? "doas is not enabled, %s" :
210+
"could not open config directory %s", dirpath);
211+
212+
dirent_count = scandir(dirpath, &dirent_table, NULL, alphasort);
213+
214+
for (i = 0; i < dirent_count; i++)
215+
{
216+
struct stat sb;
217+
size_t pathlen;
218+
219+
pathlen = snprintf(pathbuf, sizeof pathbuf, "%s/%s", dirpath, dirent_table[i]->d_name);
220+
free(dirent_table[i]);
221+
222+
/* make sure path ends in .conf */
223+
if (strcmp(pathbuf + (pathlen - 5), ".conf"))
224+
continue;
225+
226+
if (stat(pathbuf, &sb) != 0)
227+
err(1, "stat(\"%s\")", pathbuf);
228+
229+
if ((sb.st_mode & (S_IFMT)) != S_IFREG)
230+
continue;
231+
232+
parseconfig(pathbuf, checkperms);
233+
}
234+
235+
free(dirent_table);
236+
}
237+
#endif
238+
182239
static void __dead
183240
checkconfig(const char *confpath, int argc, char **argv,
184241
uid_t uid, gid_t *groups, int ngroups, uid_t target)
@@ -188,7 +245,13 @@ checkconfig(const char *confpath, int argc, char **argv,
188245
if (setresuid(uid, uid, uid) != 0)
189246
err(1, "setresuid");
190247

248+
#ifdef DOAS_CONFDIR
249+
if (isconfdir(confpath))
250+
parseconfdir(confpath, 0);
251+
else
252+
#else
191253
parseconfig(confpath, 0);
254+
#endif
192255
if (!argc)
193256
exit(0);
194257

@@ -330,7 +393,13 @@ main(int argc, char **argv)
330393
if (geteuid())
331394
errx(1, "not installed setuid");
332395

396+
#ifdef DOAS_CONFDIR
397+
if (isconfdir(DOAS_CONFDIR))
398+
parseconfdir(DOAS_CONFDIR, 1);
399+
else
400+
#else
333401
parseconfig(DOAS_CONF, 1);
402+
#endif
334403

335404
/* cmdline is used only for logging, no need to abort on truncate */
336405
(void)strlcpy(cmdline, argv[0], sizeof(cmdline));

doas.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ struct rule {
2525
const char **envlist;
2626
};
2727

28+
extern const char *yyfn;
29+
extern FILE *yyfp;
30+
2831
extern struct rule **rules;
2932
extern size_t nrules;
3033
extern int parse_errors;
@@ -33,6 +36,8 @@ extern const char *formerpath;
3336

3437
struct passwd;
3538

39+
extern int yyparse(void);
40+
3641
char **prepenv(const struct rule *, const struct passwd *,
3742
const struct passwd *);
3843

parse.y

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ typedef struct {
4949
} yystype;
5050
#define YYSTYPE yystype
5151

52+
const char *yyfn;
5253
FILE *yyfp;
5354

5455
struct rule **rules;
@@ -203,7 +204,7 @@ yyerror(const char *fmt, ...)
203204
va_start(va, fmt);
204205
vfprintf(stderr, fmt, va);
205206
va_end(va);
206-
fprintf(stderr, " at line %d\n", yylval.lineno + 1);
207+
fprintf(stderr, " at %s, line %d\n", yyfn, yylval.lineno + 1);
207208
parse_errors++;
208209
}
209210

0 commit comments

Comments
 (0)