From part 1: On Thu, 16 Mar 2017 12:04:44 +1100 <bytevolc...@safe-mail.net> wrote:
> On Wed, 15 Mar 2017 20:15:26 -0400 > "Ted Unangst" <t...@tedunangst.com> wrote: > > > Did I get it backwards? If you have setenv { HERE= there }, your > > diff changes behavior. > > > > Now I see where you are coming from. It's meant to empty $HERE, and > copy $there. Thanks, I'll look into this. > So I looked into this and gave up. Whilst I fixed the problem you mentioned, the lexer became much more complex and confusing than I expected, and I introduced a static variable. Out of interest, here is the second patch, diff from stock doas(1), adding an option to vary the "persist" timeout. The only change in behaviour I see now is that commands or arguments in the form "<keyword>=<string>" need to be escaped or placed in quotes. For example, "persist=yes", "permit=yea", "deny=nah" need escaping, but "persistence=low", "permission=granted", "denial=really" are fine. Also "keepenv { HERE= there }" amongst others, works like before. ------ Index: usr.bin/doas/doas.c =================================================================== RCS file: /cvs/src/usr.bin/doas/doas.c,v retrieving revision 1.70 diff -u -p -r1.70 doas.c --- usr.bin/doas/doas.c 9 Mar 2017 21:25:01 -0000 1.70 +++ usr.bin/doas/doas.c 16 Mar 2017 15:52:18 -0000 @@ -200,7 +200,7 @@ authuser(char *myname, char *login_style auth_session_t *as; int fd = -1; - if (persist) + if (persist > 0) fd = open("/dev/tty", O_RDWR); if (fd != -1) { if (ioctl(fd, TIOCCHKVERAUTH) == 0) @@ -233,8 +233,7 @@ authuser(char *myname, char *login_style explicit_bzero(rbuf, sizeof(rbuf)); good: if (fd != -1) { - int secs = 5 * 60; - ioctl(fd, TIOCSETVERAUTH, &secs); + ioctl(fd, TIOCSETVERAUTH, &persist); close(fd); } } @@ -361,7 +360,8 @@ main(int argc, char **argv) if (nflag) errx(1, "Authorization required"); - authuser(myname, login_style, rule->options & PERSIST); + authuser(myname, login_style, + ((rule->options & PERSIST) ? rule->persist : 0)); } if (pledge("stdio rpath getpw exec id", NULL) == -1) Index: usr.bin/doas/doas.conf.5 =================================================================== RCS file: /cvs/src/usr.bin/doas/doas.conf.5,v retrieving revision 1.31 diff -u -p -r1.31 doas.conf.5 --- usr.bin/doas/doas.conf.5 5 Dec 2016 10:58:07 -0000 1.31 +++ usr.bin/doas/doas.conf.5 16 Mar 2017 15:52:18 -0000 @@ -47,9 +47,12 @@ Options are: .Bl -tag -width keepenv .It Ic nopass The user is not required to enter a password. -.It Ic persist +.It Ic persist Ns Oo = Ns Ar time Oc After the user successfully authenticates, do not ask for a password -again for some time. +again for +.Ar time +seconds (5 minutes by default). There cannot be any whitespace on either side +of the '=' sign. .It Ic keepenv The user's environment is maintained. The default is to reset the environment, except for the variables Index: usr.bin/doas/doas.h =================================================================== RCS file: /cvs/src/usr.bin/doas/doas.h,v retrieving revision 1.12 diff -u -p -r1.12 doas.h --- usr.bin/doas/doas.h 5 Oct 2016 17:40:25 -0000 1.12 +++ usr.bin/doas/doas.h 16 Mar 2017 15:52:18 -0000 @@ -18,6 +18,7 @@ struct rule { int action; int options; + int persist; const char *ident; const char *target; const char *cmd; Index: usr.bin/doas/parse.y =================================================================== RCS file: /cvs/src/usr.bin/doas/parse.y,v retrieving revision 1.26 diff -u -p -r1.26 parse.y --- usr.bin/doas/parse.y 2 Jan 2017 01:40:20 -0000 1.26 +++ usr.bin/doas/parse.y 16 Mar 2017 15:52:18 -0000 @@ -20,9 +20,11 @@ #include <ctype.h> #include <unistd.h> #include <stdint.h> +#include <limits.h> #include <stdarg.h> #include <stdio.h> #include <string.h> +#include <errno.h> #include <err.h> #include "doas.h" @@ -32,6 +34,7 @@ typedef struct { struct { int action; int options; + int persist; const char *cmd; const char **cmdargs; const char **envlist; @@ -89,6 +92,7 @@ rule: action ident target cmd { r->action = $1.action; r->options = $1.options; r->envlist = $1.envlist; + r->persist = $1.persist; r->ident = $2.str; r->target = $3.str; r->cmd = $4.cmd; @@ -109,6 +113,7 @@ action: TPERMIT options { $$.action = PERMIT; $$.options = $2.options; $$.envlist = $2.envlist; + $$.persist = $2.persist; } | TDENY { $$.action = DENY; $$.options = 0; @@ -121,6 +126,8 @@ options: /* none */ { } | options option { $$.options = $1.options | $2.options; $$.envlist = $1.envlist; + if($2.options & PERSIST) + $$.persist = $2.persist; if (($$.options & (NOPASS|PERSIST)) == (NOPASS|PERSIST)) { yyerror("can't combine nopass and persist"); YYERROR; @@ -139,6 +146,20 @@ option: TNOPASS { } | TPERSIST { $$.options = PERSIST; $$.envlist = NULL; + $$.persist = 300; + if($1.str) { + char *ep = NULL; + errno = 0; + long number = strtol($1.str, &ep, 10); + if(*($1.str) == '\0' || *ep != '\0') { + yyerror("not a valid integer"); + YYERROR; + } else if(errno == ERANGE || number <= 0 || number > INT_MAX) { + yyerror("number out of range"); + YYERROR; + } + $$.persist = number; + } } | TKEEPENV { $$.options = KEEPENV; $$.envlist = NULL; @@ -325,10 +346,20 @@ eow: goto repeat; } if (!nonkw) { + char *eq = NULL; + if((eq = strchr(buf, '=')) != NULL) + *eq = '\0'; for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) { - if (strcmp(buf, keywords[i].word) == 0) + if (strcmp(buf, keywords[i].word) == 0) { + str = NULL; + if(eq && (str = strdup(eq + 1)) == NULL) + err(1, "strdup"); + yylval.str = str; return keywords[i].token; + } } + if(eq) + *eq = '='; } if ((str = strdup(buf)) == NULL) err(1, "strdup");