diff options
author | Vadim Zhukov <zhuk@cvs.openbsd.org> | 2015-07-22 20:15:25 +0000 |
---|---|---|
committer | Vadim Zhukov <zhuk@cvs.openbsd.org> | 2015-07-22 20:15:25 +0000 |
commit | 2654505eb843e817b1e4789a1963f042a8227f49 (patch) | |
tree | 9d1b77ea34c0fb2e5112199ae9b17b8fdf744cd0 /usr.bin/doas | |
parent | 60d8f1992b0f823ce61eff5ce7187b931d71cc56 (diff) |
Implement quoting support in doas.conf. Now you can pass environment
variables and arguments with almost any values.
As a bonus, doas will now point to exact place where syntax error occured
most of times; there is some room for improvement, though.
okay tedu@
Diffstat (limited to 'usr.bin/doas')
-rw-r--r-- | usr.bin/doas/doas.conf.5 | 20 | ||||
-rw-r--r-- | usr.bin/doas/parse.y | 117 |
2 files changed, 103 insertions, 34 deletions
diff --git a/usr.bin/doas/doas.conf.5 b/usr.bin/doas/doas.conf.5 index f64ce704cbb..2b0b7c6edd4 100644 --- a/usr.bin/doas/doas.conf.5 +++ b/usr.bin/doas/doas.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: doas.conf.5,v 1.9 2015/07/22 06:30:12 jmc Exp $ +.\" $OpenBSD: doas.conf.5,v 1.10 2015/07/22 20:15:24 zhuk Exp $ .\" .\"Copyright (c) 2015 Ted Unangst <tedu@openbsd.org> .\" @@ -82,11 +82,25 @@ alone means that command should be run without any arguments. .Pp The last matching rule determines the action taken. .Pp -The current line can be extended over multiple lines using a backslash -.Pq Sq \e . Comments can be put anywhere in the file using a hash mark .Pq Sq # , and extend to the end of the current line. +.Pp +The following quoting rules apply: +.Bl -dash +.It +The text between a pair of double quotes +.Pq Sq \&" +is taken as is. +.It +The backslash +.Pq Sq \e +escapes next character, including new line character, outside comment; +as a result, comments may not be extended over multiple lines. +.It +If quotes or backslash are used in the word, this word won't be +considered a keyword. +.El .Sh EXAMPLES The following example permits users in group wsrc to build ports, wheel to execute commands as root while keeping the environment diff --git a/usr.bin/doas/parse.y b/usr.bin/doas/parse.y index dc2d413b346..6f50f0344d4 100644 --- a/usr.bin/doas/parse.y +++ b/usr.bin/doas/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.8 2015/07/21 16:12:04 tedu Exp $ */ +/* $OpenBSD: parse.y,v 1.9 2015/07/22 20:15:24 zhuk Exp $ */ /* * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org> * @@ -190,59 +190,114 @@ struct keyword { int yylex(void) { + static int colno = 1, lineno = 1; + char buf[1024], *ebuf, *p, *str; - int i, c, next; + int i, c, quotes = 0, escape = 0, qpos = 0, nonkw = 0; p = buf; ebuf = buf + sizeof(buf); + repeat: - c = getc(yyfp); + /* skip whitespace first */ + for (c = getc(yyfp); c == ' ' || c == '\t'; c = getc(yyfp)) + colno++; + + /* check for special one-character constructions */ switch (c) { - case ' ': - case '\t': - goto repeat; /* skip spaces */ - case '\\': - next = getc(yyfp); - if (next == '\n') - goto repeat; - else - c = next; - case '\n': - case '{': - case '}': - return c; - case '#': - while ((c = getc(yyfp)) != '\n' && c != EOF) - ; /* skip comments */ - if (c == EOF) + case '\n': + colno = 1; + lineno++; + /* FALLTHROUGH */ + case '{': + case '}': + return c; + case '#': + /* skip comments; NUL is allowed; no continuation */ + while ((c = getc(yyfp)) != '\n') + if (c == EOF) + return 0; + colno = 1; + lineno++; + return c; + case EOF: return 0; - return c; - case EOF: - return 0; } - while (1) { + + /* parsing next word */ + for (;; c = getc(yyfp), colno++) { switch (c) { + case '\0': + yyerror("unallowed character NUL at " + "line %d, column %d", lineno, colno); + escape = 0; + continue; + case '\\': + escape = !escape; + if (escape) + continue; + break; case '\n': + if (quotes) + yyerror("unterminated quotes at line %d, column %d", + lineno, qpos); + if (escape) { + nonkw = 1; + escape = 0; + continue; + } + goto eow; + case EOF: + if (escape) + yyerror("unterminated escape at line %d, column %d", + lineno, colno - 1); + if (quotes) + yyerror("unterminated quotes at line %d, column %d", + lineno, qpos); + /* FALLTHROUGH */ case '{': case '}': case '#': case ' ': case '\t': - case EOF: - goto eow; + if (!escape && !quotes) + goto eow; + break; + case '"': + if (!escape) { + quotes = !quotes; + if (quotes) { + nonkw = 1; + qpos = colno; + } + continue; + } } *p++ = c; if (p == ebuf) - yyerror("too much stuff"); - c = getc(yyfp); + yyerror("too long line %d", lineno); + escape = 0; } + eow: *p = 0; if (c != EOF) ungetc(c, yyfp); - for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) { - if (strcmp(buf, keywords[i].word) == 0) - return keywords[i].token; + if (p == buf) { + /* + * There could be a number of reasons for empty buffer, and we handle + * all of them here, to avoid cluttering the main loop. + */ + if (c == EOF) + return 0; + else if (!qpos) /* accept, e.g., empty args: cmd foo args "" */ + goto repeat; + } + if (!nonkw) { + for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) { + if (strcmp(buf, keywords[i].word) == 0) + return keywords[i].token; + } } if ((str = strdup(buf)) == NULL) err(1, "strdup"); |