Hi tech@
This is a feture that came up in a chat I had with Kurt Mosiejczuk. I have been
recently reading source daily as a learning experience and decided that
implementing the feature we discussed would be a nice exercise.
The attached diff extends the configuration syntax with a new option 'confirm'
which when present on a rule triggers doas to print what command is about to
run, by whom and as what user with a question asking if the execution should
continue.
Rationale for adding this are scripts that shell out doas commands showing just
a prompt with no way for the user to tell what command he is authenticating.
with the following rule
permit confirm persist mulander as root
running a script that calls doas results in the following behavior:
$ sh test.sh
mulander wants to run 'whoami' as root. Continue? [yN]
doas: aborted by user
allowing the user to bail out or proceed. This re-uses variables already there
for syslog logging (except we don't use pwd as that would require moving getcwd
calls early and we had to introduce `first` for getchar checking).
brynet@ pointed out -n (non interactive mode), when -n is present we bail out
with the following message:
$ doas.new -n whoami
doas: Confirmation required
This email is a request for comment, roughly I want to know if others see this
feature as valuable. The diff currently lacks manpage changes, I will work on
those if the general decision is to include this feature.
I won't cry if we decide to drop this. I would have implemented it
anyways for fun :)
Regards,
Adam
Index: doas.c
===================================================================
RCS file: /cvs/src/usr.bin/doas/doas.c,v
retrieving revision 1.72
diff -u -p -r1.72 doas.c
--- doas.c 27 May 2017 09:51:07 -0000 1.72
+++ doas.c 8 Jun 2017 17:37:20 -0000
@@ -256,7 +256,7 @@ main(int argc, char **argv)
uid_t target = 0;
gid_t groups[NGROUPS_MAX + 1];
int ngroups;
- int i, ch;
+ int i, ch, first;
int sflag = 0;
int nflag = 0;
char cwdpath[PATH_MAX];
@@ -355,6 +355,20 @@ main(int argc, char **argv)
syslog(LOG_AUTHPRIV | LOG_NOTICE,
"failed command for %s: %s", myname, cmdline);
errc(1, EPERM, NULL);
+ }
+
+ if (rule->options & CONFIRM) {
+ if (nflag)
+ errx(1, "Confirmation required");
+
+ printf("%s wants to run '%s' as %s. Continue? [yN] ",
+ myname, cmdline, pw->pw_name);
+ fflush(stdout);
+ first = ch = getchar();
+ while (ch != '\n' && ch != EOF)
+ ch = getchar();
+ if (first != 'y' && first != 'Y')
+ errx(1, "aborted by user");
}
if (!(rule->options & NOPASS)) {
Index: doas.h
===================================================================
RCS file: /cvs/src/usr.bin/doas/doas.h,v
retrieving revision 1.13
diff -u -p -r1.13 doas.h
--- doas.h 6 Apr 2017 21:12:06 -0000 1.13
+++ doas.h 8 Jun 2017 17:37:20 -0000
@@ -37,3 +37,5 @@ char **prepenv(const struct rule *);
#define NOPASS 0x1
#define KEEPENV 0x2
#define PERSIST 0x4
+#define CONFIRM 0x8
+
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.bin/doas/parse.y,v
retrieving revision 1.26
diff -u -p -r1.26 parse.y
--- parse.y 2 Jan 2017 01:40:20 -0000 1.26
+++ parse.y 8 Jun 2017 17:37:20 -0000
@@ -69,7 +69,7 @@ arraylen(const char **arr)
%}
-%token TPERMIT TDENY TAS TCMD TARGS
+%token TPERMIT TDENY TAS TCMD TCONFIRM TARGS
%token TNOPASS TPERSIST TKEEPENV TSETENV
%token TSTRING
@@ -136,6 +136,9 @@ options: /* none */ {
option: TNOPASS {
$$.options = NOPASS;
$$.envlist = NULL;
+ } | TCONFIRM {
+ $$.options = CONFIRM;
+ $$.envlist = NULL;
} | TPERSIST {
$$.options = PERSIST;
$$.envlist = NULL;
@@ -209,6 +212,7 @@ static struct keyword {
{ "cmd", TCMD },
{ "args", TARGS },
{ "nopass", TNOPASS },
+ { "confirm", TCONFIRM },
{ "persist", TPERSIST },
{ "keepenv", TKEEPENV },
{ "setenv", TSETENV },