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 },

Reply via email to