diff --git a/MANIFEST b/MANIFEST index 607155418..5fc31ef41 100644 --- a/MANIFEST +++ b/MANIFEST @@ -809,6 +809,10 @@ plugins/sudoers/regress/sudoers/test9.toke.ok plugins/sudoers/regress/testsudoers/group plugins/sudoers/regress/testsudoers/test1.out.ok plugins/sudoers/regress/testsudoers/test1.sh +plugins/sudoers/regress/testsudoers/test10.out.ok +plugins/sudoers/regress/testsudoers/test10.sh +plugins/sudoers/regress/testsudoers/test11.out.ok +plugins/sudoers/regress/testsudoers/test11.sh plugins/sudoers/regress/testsudoers/test2.inc plugins/sudoers/regress/testsudoers/test2.out.ok plugins/sudoers/regress/testsudoers/test2.sh @@ -824,6 +828,8 @@ plugins/sudoers/regress/testsudoers/test7.out.ok plugins/sudoers/regress/testsudoers/test7.sh plugins/sudoers/regress/testsudoers/test8.out.ok plugins/sudoers/regress/testsudoers/test8.sh +plugins/sudoers/regress/testsudoers/test9.out.ok +plugins/sudoers/regress/testsudoers/test9.sh plugins/sudoers/regress/visudo/test1.out.ok plugins/sudoers/regress/visudo/test1.sh plugins/sudoers/regress/visudo/test10.out.ok diff --git a/NEWS b/NEWS index aa772a747..a4a8429ad 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,11 @@ What's new in Sudo 1.9.1 option to allow replaying a session that is still in progress, similar to "tail -f". + * The @include and @includedir directives can be used in sudoers + instead of #include and #includedir. In addition, include paths + may now have embedded white space by either using a double-quoted + string or escaping the space characters with a backslash. + What's new in Sudo 1.9.0 * Fixed a test failure in the strsig_test regress test on FreeBSD. diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in index 42171137a..561501b24 100644 --- a/doc/sudoers.man.in +++ b/doc/sudoers.man.in @@ -25,7 +25,7 @@ .nr BA @BAMAN@ .nr LC @LCMAN@ .nr PS @PSMAN@ -.TH "SUDOERS" "@mansectform@" "April 30, 2020" "Sudo @PACKAGE_VERSION@" "File Formats Manual" +.TH "SUDOERS" "@mansectform@" "May 19, 2020" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .nh .if n .ad l .SH "NAME" @@ -1864,12 +1864,17 @@ It is possible to include other files from within the \fIsudoers\fR file currently being parsed using the +\fR@include\fR +and +\fR@includedir\fR +directives. +For compatibility with sudo versions prior to 1.9.1, \fR#include\fR and \fR#includedir\fR -directives. +are also accepted. .PP -This can be used, for example, to keep a site-wide +An include file can be used, for example, to keep a site-wide \fIsudoers\fR file in addition to a local, per-machine file. For the sake of this example the site-wide @@ -1882,13 +1887,12 @@ To include \fI/etc/sudoers.local\fR from within \fI/etc/sudoers\fR -we would use the -following line in +one would use the following line in \fI/etc/sudoers\fR: .nf .sp .RS 4n -#include /etc/sudoers.local +@include /etc/sudoers.local .RE .fi .PP @@ -1907,6 +1911,16 @@ Files that are included may themselves include other files. A hard limit of 128 nested include files is enforced to prevent include file loops. .PP +The path to the include file may contain white space if it is +escaped with a backslash +(\(oq\e\(cq). +Alternately, the entire path may be enclosed in double quotes +(\&""), +in which case no escaping is necessary. +To include a literal backslash in the path, +\(oq\e\e\(cq +should be used. +.PP If the path to the include file is not fully-qualified (does not begin with a \(oq/\(cq), @@ -1918,7 +1932,7 @@ contains the line: .nf .sp .RS 4n -\fR#include sudoers.local\fR +\fR@include sudoers.local\fR .RE .fi .PP @@ -1934,7 +1948,7 @@ then .nf .sp .RS 4n -#include /etc/sudoers.%h +@include /etc/sudoers.%h .RE .fi .PP @@ -1944,7 +1958,7 @@ to include the file \fI/etc/sudoers.xerxes\fR. .PP The -\fR#includedir\fR +\fR@includedir\fR directive can be used to create a \fIsudoers.d\fR directory that the system package manager can drop @@ -1954,7 +1968,7 @@ For example, given: .nf .sp .RS 4n -#includedir /etc/sudoers.d +@includedir /etc/sudoers.d .RE .fi .PP @@ -1981,14 +1995,14 @@ Using a consistent number of leading zeroes in the file names can be used to avoid such problems. After parsing the files in the directory, control returns to the file that contained the -\fR#includedir\fR +\fR@includedir\fR directive. .PP Note that unlike files included via -\fR#include\fR, +\fR@include\fR, \fBvisudo\fR will not edit the files in a -\fR#includedir\fR +\fR@includedir\fR directory unless one of them contains a syntax error. It is still possible to run \fBvisudo\fR @@ -4105,7 +4119,7 @@ Entries in this file should either be of the form \(lq\fRVARIABLE=value\fR\(rq or \(lq\fRexport VARIABLE=value\fR\(rq. -The value may optionally be surrounded by single or double quotes. +The value may optionally be enclosed in single or double quotes. Variables in this file are only added if the variable does not already exist in the environment. This file is considered to be part of the security policy, @@ -4332,7 +4346,7 @@ Entries in this file should either be of the form \(lq\fRVARIABLE=value\fR\(rq or \(lq\fRexport VARIABLE=value\fR\(rq. -The value may optionally be surrounded by single or double quotes. +The value may optionally be enclosed in single or double quotes. Variables in this file are only added if the variable does not already exist in the environment. Unlike diff --git a/doc/sudoers.mdoc.in b/doc/sudoers.mdoc.in index 95dbc2729..130687186 100644 --- a/doc/sudoers.mdoc.in +++ b/doc/sudoers.mdoc.in @@ -24,7 +24,7 @@ .nr BA @BAMAN@ .nr LC @LCMAN@ .nr PS @PSMAN@ -.Dd April 30, 2020 +.Dd May 19, 2020 .Dt SUDOERS @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -1753,12 +1753,17 @@ It is possible to include other files from within the .Em sudoers file currently being parsed using the +.Li @include +and +.Li @includedir +directives. +For compatibility with sudo versions prior to 1.9.1, .Li #include and .Li #includedir -directives. +are also accepted. .Pp -This can be used, for example, to keep a site-wide +An include file can be used, for example, to keep a site-wide .Em sudoers file in addition to a local, per-machine file. For the sake of this example the site-wide @@ -1771,11 +1776,10 @@ To include .Pa /etc/sudoers.local from within .Pa /etc/sudoers -we would use the -following line in +one would use the following line in .Pa /etc/sudoers : .Bd -literal -offset 4n -#include /etc/sudoers.local +@include /etc/sudoers.local .Ed .Pp When @@ -1793,6 +1797,16 @@ Files that are included may themselves include other files. A hard limit of 128 nested include files is enforced to prevent include file loops. .Pp +The path to the include file may contain white space if it is +escaped with a backslash +.Pq Ql \e . +Alternately, the entire path may be enclosed in double quotes +.Pq \&"" , +in which case no escaping is necessary. +To include a literal backslash in the path, +.Ql \e\e +should be used. +.Pp If the path to the include file is not fully-qualified (does not begin with a .Ql / ) , @@ -1802,7 +1816,7 @@ For example, if .Pa /etc/sudoers contains the line: .Bd -literal -offset 4n -.Li #include sudoers.local +.Li @include sudoers.local .Ed .Pp the file that will be included is @@ -1815,7 +1829,7 @@ In other words, if the machine's host name is .Dq xerxes , then .Bd -literal -offset 4n -#include /etc/sudoers.%h +@include /etc/sudoers.%h .Ed .Pp will cause @@ -1824,7 +1838,7 @@ to include the file .Pa /etc/sudoers.xerxes . .Pp The -.Li #includedir +.Li @includedir directive can be used to create a .Pa sudoers.d directory that the system package manager can drop @@ -1832,7 +1846,7 @@ directory that the system package manager can drop file rules into as part of package installation. For example, given: .Bd -literal -offset 4n -#includedir /etc/sudoers.d +@includedir /etc/sudoers.d .Ed .Pp .Nm sudo @@ -1858,14 +1872,14 @@ Using a consistent number of leading zeroes in the file names can be used to avoid such problems. After parsing the files in the directory, control returns to the file that contained the -.Li #includedir +.Li @includedir directive. .Pp Note that unlike files included via -.Li #include , +.Li @include , .Nm visudo will not edit the files in a -.Li #includedir +.Li @includedir directory unless one of them contains a syntax error. It is still possible to run .Nm visudo @@ -3849,7 +3863,7 @@ Entries in this file should either be of the form .Dq Li VARIABLE=value or .Dq Li export VARIABLE=value . -The value may optionally be surrounded by single or double quotes. +The value may optionally be enclosed in single or double quotes. Variables in this file are only added if the variable does not already exist in the environment. This file is considered to be part of the security policy, @@ -4045,7 +4059,7 @@ Entries in this file should either be of the form .Dq Li VARIABLE=value or .Dq Li export VARIABLE=value . -The value may optionally be surrounded by single or double quotes. +The value may optionally be enclosed in single or double quotes. Variables in this file are only added if the variable does not already exist in the environment. Unlike diff --git a/plugins/sudoers/gram.c b/plugins/sudoers/gram.c index 50d05a229..f9df4c867 100644 --- a/plugins/sudoers/gram.c +++ b/plugins/sudoers/gram.c @@ -136,44 +136,46 @@ typedef union { #define USERGROUP 262 #define WORD 263 #define DIGEST 264 -#define DEFAULTS 265 -#define DEFAULTS_HOST 266 -#define DEFAULTS_USER 267 -#define DEFAULTS_RUNAS 268 -#define DEFAULTS_CMND 269 -#define NOPASSWD 270 -#define PASSWD 271 -#define NOEXEC 272 -#define EXEC 273 -#define SETENV 274 -#define NOSETENV 275 -#define LOG_INPUT 276 -#define NOLOG_INPUT 277 -#define LOG_OUTPUT 278 -#define NOLOG_OUTPUT 279 -#define MAIL 280 -#define NOMAIL 281 -#define FOLLOWLNK 282 -#define NOFOLLOWLNK 283 -#define ALL 284 -#define COMMENT 285 -#define HOSTALIAS 286 -#define CMNDALIAS 287 -#define USERALIAS 288 -#define RUNASALIAS 289 -#define ERROR 290 -#define TYPE 291 -#define ROLE 292 -#define PRIVS 293 -#define LIMITPRIVS 294 -#define CMND_TIMEOUT 295 -#define NOTBEFORE 296 -#define NOTAFTER 297 -#define MYSELF 298 -#define SHA224_TOK 299 -#define SHA256_TOK 300 -#define SHA384_TOK 301 -#define SHA512_TOK 302 +#define INCLUDE 265 +#define INCLUDEDIR 266 +#define DEFAULTS 267 +#define DEFAULTS_HOST 268 +#define DEFAULTS_USER 269 +#define DEFAULTS_RUNAS 270 +#define DEFAULTS_CMND 271 +#define NOPASSWD 272 +#define PASSWD 273 +#define NOEXEC 274 +#define EXEC 275 +#define SETENV 276 +#define NOSETENV 277 +#define LOG_INPUT 278 +#define NOLOG_INPUT 279 +#define LOG_OUTPUT 280 +#define NOLOG_OUTPUT 281 +#define MAIL 282 +#define NOMAIL 283 +#define FOLLOWLNK 284 +#define NOFOLLOWLNK 285 +#define ALL 286 +#define COMMENT 287 +#define HOSTALIAS 288 +#define CMNDALIAS 289 +#define USERALIAS 290 +#define RUNASALIAS 291 +#define ERROR 292 +#define TYPE 293 +#define ROLE 294 +#define PRIVS 295 +#define LIMITPRIVS 296 +#define CMND_TIMEOUT 297 +#define NOTBEFORE 298 +#define NOTAFTER 299 +#define MYSELF 300 +#define SHA224_TOK 301 +#define SHA256_TOK 302 +#define SHA384_TOK 303 +#define SHA512_TOK 304 #define YYERRCODE 256 #if defined(__cplusplus) || defined(__STDC__) const short sudoerslhs[] = @@ -182,17 +184,17 @@ short sudoerslhs[] = #endif { -1, 0, 0, 33, 33, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 4, 4, 3, 3, - 3, 3, 3, 21, 21, 20, 11, 11, 9, 9, - 9, 9, 9, 2, 2, 1, 31, 31, 31, 31, - 32, 32, 7, 7, 6, 6, 28, 29, 30, 24, - 25, 26, 27, 18, 18, 19, 19, 19, 19, 19, - 23, 23, 23, 23, 23, 23, 23, 23, 22, 22, + 34, 34, 34, 34, 34, 34, 34, 34, 4, 4, + 3, 3, 3, 3, 3, 21, 21, 20, 11, 11, + 9, 9, 9, 9, 9, 2, 2, 1, 31, 31, + 31, 31, 32, 32, 7, 7, 6, 6, 28, 29, + 30, 24, 25, 26, 27, 18, 18, 19, 19, 19, + 19, 19, 23, 23, 23, 23, 23, 23, 23, 23, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 5, 5, 5, 36, 36, 39, 10, - 10, 37, 37, 40, 8, 8, 38, 38, 41, 35, - 35, 42, 14, 14, 12, 12, 13, 13, 13, 13, - 13, 17, 17, 15, 15, 16, 16, 16, + 22, 22, 22, 22, 22, 5, 5, 5, 36, 36, + 39, 10, 10, 37, 37, 40, 8, 8, 38, 38, + 41, 35, 35, 42, 14, 14, 12, 12, 13, 13, + 13, 13, 13, 17, 17, 15, 15, 16, 16, 16, }; #if defined(__cplusplus) || defined(__STDC__) const short sudoerslen[] = @@ -201,17 +203,17 @@ short sudoerslen[] = #endif { 2, 0, 1, 1, 2, 1, 2, 2, 2, 2, 2, - 2, 2, 3, 3, 3, 3, 1, 3, 1, 2, - 3, 3, 3, 1, 3, 3, 1, 2, 1, 1, - 1, 1, 1, 1, 3, 4, 3, 3, 3, 3, - 1, 3, 1, 2, 1, 2, 3, 3, 3, 3, - 3, 3, 3, 0, 3, 0, 1, 3, 2, 1, - 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 1, 1, 1, 1, 3, 3, 1, - 3, 1, 3, 3, 1, 3, 1, 3, 3, 1, - 3, 3, 1, 3, 1, 2, 1, 1, 1, 1, - 1, 1, 3, 1, 2, 1, 1, 1, + 2, 2, 2, 2, 3, 3, 3, 3, 1, 3, + 1, 2, 3, 3, 3, 1, 3, 3, 1, 2, + 1, 1, 1, 1, 1, 1, 3, 4, 3, 3, + 3, 3, 1, 3, 1, 2, 1, 2, 3, 3, + 3, 3, 3, 3, 3, 0, 3, 0, 1, 3, + 2, 1, 0, 2, 2, 2, 2, 2, 2, 2, + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 1, 1, 1, 3, + 3, 1, 3, 1, 3, 3, 1, 3, 1, 3, + 3, 1, 3, 3, 1, 3, 1, 2, 1, 1, + 1, 1, 1, 1, 3, 1, 2, 1, 1, 1, }; #if defined(__cplusplus) || defined(__STDC__) const short sudoersdefred[] = @@ -219,188 +221,210 @@ const short sudoersdefred[] = short sudoersdefred[] = #endif { 0, - 0, 107, 109, 110, 111, 0, 0, 0, 0, 0, - 108, 5, 0, 0, 0, 0, 0, 0, 103, 105, - 0, 0, 3, 6, 0, 0, 17, 0, 29, 32, - 31, 33, 30, 0, 27, 0, 90, 0, 0, 86, - 85, 84, 0, 0, 0, 0, 0, 45, 43, 95, - 0, 41, 0, 0, 0, 87, 0, 0, 92, 0, - 0, 100, 0, 0, 97, 106, 0, 0, 24, 0, - 4, 0, 0, 0, 20, 0, 28, 0, 0, 0, - 0, 46, 0, 0, 0, 0, 0, 0, 0, 44, - 0, 0, 0, 0, 0, 0, 0, 0, 104, 0, - 0, 21, 22, 23, 18, 91, 37, 38, 39, 40, - 96, 42, 0, 88, 0, 93, 0, 101, 0, 98, - 0, 34, 0, 61, 25, 0, 0, 0, 0, 0, - 116, 118, 117, 0, 112, 114, 0, 0, 55, 35, - 0, 0, 0, 0, 0, 0, 0, 0, 65, 66, - 67, 68, 64, 62, 63, 115, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 82, 83, 80, 81, 36, - 113, 51, 50, 52, 53, 47, 48, 49, + 0, 109, 111, 112, 113, 0, 0, 0, 0, 0, + 0, 0, 110, 5, 0, 0, 0, 0, 0, 0, + 105, 107, 0, 0, 3, 6, 7, 8, 0, 0, + 19, 0, 31, 34, 33, 35, 32, 0, 29, 0, + 92, 0, 0, 88, 87, 86, 0, 0, 0, 0, + 0, 47, 45, 97, 0, 43, 0, 0, 0, 89, + 0, 0, 94, 0, 0, 102, 0, 0, 99, 108, + 0, 0, 26, 0, 4, 0, 0, 0, 22, 0, + 30, 0, 0, 0, 0, 48, 0, 0, 0, 0, + 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, + 0, 0, 106, 0, 0, 23, 24, 25, 20, 93, + 39, 40, 41, 42, 98, 44, 0, 90, 0, 95, + 0, 103, 0, 100, 0, 36, 0, 63, 27, 0, + 0, 0, 0, 0, 118, 120, 119, 0, 114, 116, + 0, 0, 57, 37, 0, 0, 0, 0, 0, 0, + 0, 0, 67, 68, 69, 70, 66, 64, 65, 117, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 84, + 85, 82, 83, 38, 115, 53, 52, 54, 55, 49, + 50, 51, }; #if defined(__cplusplus) || defined(__STDC__) const short sudoersdgoto[] = #else short sudoersdgoto[] = #endif - { 18, - 122, 123, 27, 28, 48, 49, 50, 51, 35, 68, - 37, 19, 20, 21, 135, 136, 137, 124, 128, 69, - 70, 148, 130, 149, 150, 151, 152, 153, 154, 155, - 52, 53, 22, 23, 61, 55, 58, 64, 56, 59, - 65, 62, + { 20, + 126, 127, 31, 32, 52, 53, 54, 55, 39, 72, + 41, 21, 22, 23, 139, 140, 141, 128, 132, 73, + 74, 152, 134, 153, 154, 155, 156, 157, 158, 159, + 56, 57, 24, 25, 65, 59, 62, 68, 60, 63, + 69, 66, }; #if defined(__cplusplus) || defined(__STDC__) const short sudoerssindex[] = #else short sudoerssindex[] = #endif - { 512, - -272, 0, 0, 0, 0, -23, 227, -19, -19, -5, - 0, 0, -239, -234, -231, -227, -225, 0, 0, 0, - -33, 512, 0, 0, -4, -224, 0, -2, 0, 0, - 0, 0, 0, -208, 0, -28, 0, -24, -24, 0, - 0, 0, -240, -11, 2, 3, 8, 0, 0, 0, - -21, 0, -12, -15, 9, 0, -7, 16, 0, -3, - 17, 0, 18, 20, 0, 0, -19, -18, 0, 22, - 0, -223, -207, -182, 0, -23, 0, 227, -2, -2, - -2, 0, -181, -180, -179, -178, -5, -2, -230, 0, - 227, -239, -5, -234, -19, -231, -19, -227, 0, 47, - 227, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 44, 0, 48, 0, 50, 0, 50, 0, - -29, 0, 51, 0, 0, 289, -36, 52, 47, -193, - 0, 0, 0, -233, 0, 0, 61, 289, 0, 0, - 45, 53, 55, 56, 57, 58, 59, 450, 0, 0, - 0, 0, 0, 0, 0, 0, 289, 61, -155, -154, - -153, -151, -150, -141, -140, 0, 0, 0, 0, 0, + { 703, + -278, 0, 0, 0, 0, -241, -231, -19, 51, 59, + 59, -28, 0, 0, -215, -212, -211, -210, -233, 0, + 0, 0, -26, 703, 0, 0, 0, 0, -12, -232, + 0, 6, 0, 0, 0, 0, 0, -222, 0, -33, + 0, -31, -31, 0, 0, 0, -242, 8, 10, 11, + 13, 0, 0, 0, -23, 0, -9, 17, 14, 0, + 18, 22, 0, 20, 24, 0, 25, 27, 0, 0, + 59, -38, 0, 29, 0, -180, -175, -173, 0, -19, + 0, 51, 6, 6, 6, 0, -171, -170, -168, -167, + -28, 6, -227, 0, 51, -215, -28, -212, 59, -211, + 59, -210, 0, 58, 51, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 47, 0, 55, 0, + 56, 0, 56, 0, -7, 0, 57, 0, 0, -25, + -2, 61, 58, -236, 0, 0, 0, -246, 0, 0, + 60, -25, 0, 0, 42, 44, 46, 50, 52, 53, + 54, 620, 0, 0, 0, 0, 0, 0, 0, 0, + -25, 60, -151, -147, -146, -145, -144, -143, -142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,}; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,}; #if defined(__cplusplus) || defined(__STDC__) const short sudoersrindex[] = #else short sudoersrindex[] = #endif - { 124, + { 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 125, 0, 0, 1, 0, 0, 145, 0, 0, + 0, 0, 0, 123, 0, 0, 0, 0, 1, 0, + 0, 217, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 253, 0, + 0, 297, 0, 0, 333, 0, 0, 369, 0, 0, + 0, 0, 0, 405, 0, 0, 0, 0, 0, 0, + 0, 0, 441, 477, 513, 0, 0, 0, 0, 0, + 0, 549, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 572, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 37, 0, 73, 0, + 109, 0, 145, 0, 83, 0, 181, 0, 0, 84, + 85, 0, 572, 653, 0, 0, 0, 0, 0, 0, + 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 159, 0, 0, 193, 0, 0, - 207, 0, 0, 241, 0, 0, 0, 0, 0, 275, - 0, 0, 0, 0, 0, 0, 0, 0, 309, 323, - 357, 0, 0, 0, 0, 0, 0, 371, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 404, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 49, 0, 63, 0, 97, 0, - 85, 0, 111, 0, 0, 86, 87, 0, 404, 483, - 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,}; + 0, 0,}; #if defined(__cplusplus) || defined(__STDC__) const short sudoersgindex[] = #else short sudoersgindex[] = #endif { 0, - 4, 0, 60, 26, 89, 81, -80, 42, 103, -1, - 62, 71, 122, -6, -16, 12, 5, 0, 0, 41, + -4, 0, 63, 12, 88, 75, -87, 33, 95, -6, + 62, 65, 118, 9, -22, 2, -1, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 64, 0, 0, 126, 0, 0, 0, 0, 65, 66, - 54, 67, + 45, 0, 0, 124, 0, 0, 0, 0, 64, 49, + 48, 66, }; -#define YYTABLESIZE 801 +#define YYTABLESIZE 994 #if defined(__cplusplus) || defined(__STDC__) const short sudoerstable[] = #else short sudoerstable[] = #endif - { 34, - 19, 38, 39, 17, 26, 36, 111, 67, 26, 26, - 67, 26, 24, 17, 89, 78, 40, 41, 54, 67, - 43, 138, 87, 57, 131, 78, 60, 43, 126, 132, - 63, 89, 2, 19, 75, 3, 4, 5, 73, 102, - 74, 76, 100, 42, 19, 91, 83, 89, 94, 29, - 133, 30, 31, 93, 32, 103, 72, 95, 11, 84, - 85, 79, 102, 80, 81, 86, 92, 180, 44, 45, - 46, 47, 89, 94, 96, 33, 88, 98, 97, 101, - 104, 94, 107, 108, 109, 110, 121, 78, 117, 113, - 119, 87, 139, 67, 129, 102, 99, 141, 142, 143, - 144, 145, 146, 147, 157, 159, 94, 182, 183, 184, - 26, 185, 186, 160, 127, 161, 162, 163, 164, 165, - 102, 187, 188, 1, 2, 56, 60, 57, 59, 99, - 58, 82, 140, 90, 115, 105, 77, 99, 66, 106, - 181, 125, 158, 26, 12, 156, 0, 71, 0, 0, - 0, 120, 112, 0, 99, 0, 114, 0, 9, 116, - 0, 0, 118, 0, 0, 0, 0, 0, 26, 0, - 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, + { 30, + 21, 30, 40, 115, 47, 82, 38, 138, 26, 30, + 82, 135, 71, 30, 44, 45, 136, 71, 42, 43, + 91, 27, 104, 47, 2, 19, 79, 3, 4, 5, + 77, 28, 78, 21, 93, 33, 91, 34, 35, 137, + 36, 71, 58, 46, 21, 61, 64, 67, 76, 80, + 130, 83, 13, 84, 85, 142, 145, 146, 147, 148, + 149, 150, 151, 37, 184, 87, 92, 88, 89, 91, + 90, 96, 96, 48, 49, 50, 51, 95, 97, 98, + 99, 100, 106, 38, 102, 101, 105, 107, 117, 108, + 82, 19, 111, 112, 91, 113, 114, 125, 91, 71, + 133, 143, 163, 161, 164, 96, 165, 121, 104, 123, + 166, 186, 167, 168, 169, 187, 188, 189, 190, 191, + 192, 1, 2, 58, 62, 59, 61, 60, 144, 119, + 96, 94, 81, 131, 86, 103, 70, 116, 185, 160, + 162, 104, 109, 110, 101, 129, 120, 75, 0, 124, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, + 0, 0, 0, 0, 0, 122, 104, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, + 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, + 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 28, 0, 0, 14, 0, 0, 0, + 0, 0, 0, 0, 0, 29, 0, 29, 44, 45, + 0, 33, 135, 34, 35, 29, 36, 136, 28, 29, + 0, 0, 0, 0, 0, 0, 0, 44, 45, 14, + 2, 0, 11, 3, 4, 5, 21, 46, 21, 37, + 137, 21, 21, 21, 0, 21, 21, 21, 21, 21, + 21, 21, 48, 49, 50, 51, 46, 0, 13, 0, + 0, 0, 0, 0, 0, 11, 21, 21, 21, 21, + 21, 21, 91, 0, 91, 0, 12, 91, 91, 91, + 0, 91, 91, 91, 91, 91, 91, 91, 33, 0, + 34, 35, 0, 36, 0, 0, 2, 0, 0, 3, + 4, 5, 91, 91, 91, 91, 91, 91, 96, 12, + 96, 0, 10, 96, 96, 96, 37, 96, 96, 96, + 96, 96, 96, 96, 13, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 96, 96, + 96, 96, 96, 96, 104, 10, 104, 0, 13, 104, + 104, 104, 0, 104, 104, 104, 104, 104, 104, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 29, 10, 30, 31, 2, 32, - 25, 3, 4, 5, 25, 25, 0, 25, 2, 8, - 11, 3, 4, 5, 40, 41, 0, 0, 0, 0, - 33, 40, 41, 0, 11, 0, 19, 0, 19, 34, - 0, 19, 19, 19, 11, 19, 19, 19, 19, 19, - 89, 42, 89, 11, 7, 89, 89, 89, 42, 89, - 89, 89, 89, 89, 19, 19, 19, 19, 19, 19, - 0, 0, 0, 44, 45, 46, 47, 0, 89, 89, - 89, 89, 89, 89, 94, 0, 94, 7, 15, 94, - 94, 94, 0, 94, 94, 94, 94, 94, 102, 0, - 102, 134, 13, 102, 102, 102, 0, 102, 102, 102, - 102, 102, 94, 94, 94, 94, 94, 94, 0, 0, - 0, 15, 0, 0, 0, 0, 102, 102, 102, 102, - 102, 102, 99, 0, 99, 13, 14, 99, 99, 99, - 0, 99, 99, 99, 99, 99, 26, 0, 26, 0, - 16, 26, 26, 26, 0, 26, 26, 26, 26, 26, - 99, 99, 99, 99, 99, 99, 0, 0, 0, 14, - 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, - 12, 0, 12, 16, 0, 12, 12, 12, 0, 12, - 12, 12, 12, 12, 9, 0, 9, 0, 0, 9, - 9, 9, 0, 9, 9, 9, 9, 9, 12, 12, - 12, 12, 12, 12, 0, 0, 54, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 9, 9, 10, 0, + 0, 0, 0, 0, 104, 104, 104, 104, 104, 104, + 101, 13, 101, 0, 9, 101, 101, 101, 0, 101, + 101, 101, 101, 101, 101, 101, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 101, 101, 101, 101, 101, 101, 28, 9, 28, 0, + 17, 28, 28, 28, 0, 28, 28, 28, 28, 28, + 28, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 28, 28, 28, 28, + 28, 28, 14, 17, 14, 0, 15, 14, 14, 14, + 0, 14, 14, 14, 14, 14, 14, 14, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 14, 14, 14, 14, 14, 14, 11, 15, + 11, 0, 16, 11, 11, 11, 0, 11, 11, 11, + 11, 11, 11, 11, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, + 11, 11, 11, 11, 0, 16, 0, 0, 18, 0, + 0, 0, 12, 0, 12, 0, 0, 12, 12, 12, + 0, 12, 12, 12, 12, 12, 12, 12, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 18, 12, 12, 12, 12, 12, 12, 10, 0, 10, 0, 0, 10, 10, 10, 0, 10, 10, 10, - 10, 10, 8, 0, 8, 0, 0, 8, 8, 8, - 0, 8, 8, 8, 8, 8, 10, 10, 10, 10, - 10, 10, 43, 0, 29, 0, 30, 31, 0, 32, - 8, 8, 8, 8, 8, 8, 11, 0, 11, 0, - 0, 11, 11, 11, 0, 11, 11, 11, 11, 11, - 33, 0, 0, 0, 0, 69, 0, 0, 0, 0, - 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, - 7, 0, 7, 0, 0, 7, 7, 7, 0, 7, - 7, 7, 7, 7, 17, 0, 131, 0, 0, 0, - 0, 132, 0, 0, 0, 0, 0, 0, 7, 7, - 7, 7, 7, 7, 15, 0, 15, 0, 0, 15, - 15, 15, 133, 15, 15, 15, 15, 15, 13, 0, - 13, 0, 0, 13, 13, 13, 0, 13, 13, 13, - 13, 13, 15, 15, 15, 15, 15, 15, 0, 0, - 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, - 13, 13, 14, 0, 14, 0, 0, 14, 14, 14, - 0, 14, 14, 14, 14, 14, 16, 0, 16, 0, - 0, 16, 16, 16, 0, 16, 16, 16, 16, 16, - 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, - 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, - 54, 54, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 0, 0, - 0, 0, 0, 0, 54, 54, 54, 54, 54, 54, - 54, 0, 54, 54, 54, 54, 40, 41, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 42, 0, 0, 0, 0, 0, 69, - 69, 0, 0, 0, 0, 0, 0, 0, 44, 45, - 46, 47, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 1, 0, 2, - 0, 0, 3, 4, 5, 0, 6, 7, 8, 9, - 10, 69, 69, 69, 69, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 11, 12, 13, 14, 15, - 16, + 10, 10, 10, 10, 56, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, + 10, 10, 10, 10, 13, 0, 13, 0, 0, 13, + 13, 13, 0, 13, 13, 13, 13, 13, 13, 13, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 47, 0, 13, 13, 13, 13, 13, 13, + 9, 0, 9, 0, 0, 9, 9, 9, 0, 9, + 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 71, 0, 0, 0, 0, + 9, 9, 9, 9, 9, 9, 17, 0, 17, 0, + 0, 17, 17, 17, 0, 17, 17, 17, 17, 17, + 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, + 17, 17, 15, 0, 15, 19, 0, 15, 15, 15, + 0, 15, 15, 15, 15, 15, 15, 15, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 15, 15, 15, 15, 15, 15, 16, 0, + 16, 0, 0, 16, 16, 16, 0, 16, 16, 16, + 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, + 16, 16, 16, 16, 18, 0, 18, 0, 0, 18, + 18, 18, 0, 18, 18, 18, 18, 18, 18, 18, + 0, 0, 0, 0, 0, 0, 0, 0, 56, 56, + 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, + 0, 0, 0, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 0, 0, + 0, 0, 0, 0, 56, 56, 56, 56, 56, 56, + 56, 0, 56, 56, 56, 56, 44, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 46, 0, 0, 0, 71, + 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 49, 50, 51, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 71, 71, 71, 71, 0, 1, 0, + 2, 0, 0, 3, 4, 5, 0, 6, 7, 8, + 9, 10, 11, 12, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, + 15, 16, 17, 18, }; #if defined(__cplusplus) || defined(__STDC__) const short sudoerscheck[] = @@ -408,93 +432,112 @@ const short sudoerscheck[] = short sudoerscheck[] = #endif { 33, - 0, 8, 9, 33, 33, 7, 87, 44, 33, 33, - 44, 33, 285, 33, 0, 44, 257, 258, 258, 44, - 33, 58, 44, 258, 258, 44, 258, 33, 58, 263, - 258, 44, 258, 33, 259, 261, 262, 263, 43, 263, - 45, 44, 61, 284, 44, 61, 58, 33, 0, 258, - 284, 260, 261, 61, 263, 263, 61, 61, 284, 58, - 58, 36, 0, 38, 39, 58, 58, 148, 299, 300, - 301, 302, 58, 58, 58, 284, 51, 58, 61, 58, - 263, 33, 264, 264, 264, 264, 40, 44, 95, 91, - 97, 44, 41, 44, 44, 33, 0, 291, 292, 293, - 294, 295, 296, 297, 44, 61, 58, 263, 263, 263, - 0, 263, 263, 61, 121, 61, 61, 61, 61, 61, - 58, 263, 263, 0, 0, 41, 41, 41, 41, 33, - 41, 43, 129, 53, 93, 76, 34, 67, 17, 78, - 157, 101, 138, 33, 0, 134, -1, 22, -1, -1, - -1, 98, 89, -1, 58, -1, 92, -1, 0, 94, - -1, -1, 96, -1, -1, -1, -1, -1, 58, -1, + 0, 33, 9, 91, 33, 44, 33, 33, 287, 33, + 44, 258, 44, 33, 257, 258, 263, 44, 10, 11, + 44, 263, 61, 33, 258, 33, 259, 261, 262, 263, + 43, 263, 45, 33, 44, 258, 0, 260, 261, 286, + 263, 44, 258, 286, 44, 258, 258, 258, 61, 44, + 58, 40, 286, 42, 43, 58, 293, 294, 295, 296, + 297, 298, 299, 286, 152, 58, 55, 58, 58, 33, + 58, 58, 0, 301, 302, 303, 304, 61, 61, 58, + 61, 58, 263, 33, 58, 61, 58, 263, 95, 263, + 44, 33, 264, 264, 58, 264, 264, 40, 44, 44, + 44, 41, 61, 44, 61, 33, 61, 99, 0, 101, + 61, 263, 61, 61, 61, 263, 263, 263, 263, 263, + 263, 0, 0, 41, 41, 41, 41, 41, 133, 97, + 58, 57, 38, 125, 47, 71, 19, 93, 161, 138, + 142, 33, 80, 82, 0, 105, 98, 24, -1, 102, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 96, + -1, -1, -1, -1, -1, 100, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, -1, + 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 33, 0, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, + -1, -1, 58, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 33, -1, -1, 0, -1, -1, -1, + -1, -1, -1, -1, -1, 259, -1, 259, 257, 258, + -1, 258, 258, 260, 261, 259, 263, 263, 58, 259, + -1, -1, -1, -1, -1, -1, -1, 257, 258, 33, + 258, -1, 0, 261, 262, 263, 256, 286, 258, 286, + 286, 261, 262, 263, -1, 265, 266, 267, 268, 269, + 270, 271, 301, 302, 303, 304, 286, -1, 286, -1, + -1, -1, -1, -1, -1, 33, 286, 287, 288, 289, + 290, 291, 256, -1, 258, -1, 0, 261, 262, 263, + -1, 265, 266, 267, 268, 269, 270, 271, 258, -1, + 260, 261, -1, 263, -1, -1, 258, -1, -1, 261, + 262, 263, 286, 287, 288, 289, 290, 291, 256, 33, + 258, -1, 0, 261, 262, 263, 286, 265, 266, 267, + 268, 269, 270, 271, 286, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 286, 287, + 288, 289, 290, 291, 256, 33, 258, -1, 0, 261, + 262, 263, -1, 265, 266, 267, 268, 269, 270, 271, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 258, 33, 260, 261, 258, 263, - 259, 261, 262, 263, 259, 259, -1, 259, 258, 33, - 0, 261, 262, 263, 257, 258, -1, -1, -1, -1, - 284, 257, 258, -1, 284, -1, 256, -1, 258, 33, - -1, 261, 262, 263, 284, 265, 266, 267, 268, 269, - 256, 284, 258, 33, 0, 261, 262, 263, 284, 265, - 266, 267, 268, 269, 284, 285, 286, 287, 288, 289, - -1, -1, -1, 299, 300, 301, 302, -1, 284, 285, - 286, 287, 288, 289, 256, -1, 258, 33, 0, 261, - 262, 263, -1, 265, 266, 267, 268, 269, 256, -1, - 258, 33, 0, 261, 262, 263, -1, 265, 266, 267, - 268, 269, 284, 285, 286, 287, 288, 289, -1, -1, - -1, 33, -1, -1, -1, -1, 284, 285, 286, 287, - 288, 289, 256, -1, 258, 33, 0, 261, 262, 263, - -1, 265, 266, 267, 268, 269, 256, -1, 258, -1, + -1, -1, -1, -1, 286, 287, 288, 289, 290, 291, + 256, 33, 258, -1, 0, 261, 262, 263, -1, 265, + 266, 267, 268, 269, 270, 271, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 286, 287, 288, 289, 290, 291, 256, 33, 258, -1, 0, 261, 262, 263, -1, 265, 266, 267, 268, 269, - 284, 285, 286, 287, 288, 289, -1, -1, -1, 33, - -1, -1, -1, -1, 284, 285, 286, 287, 288, 289, - 256, -1, 258, 33, -1, 261, 262, 263, -1, 265, - 266, 267, 268, 269, 256, -1, 258, -1, -1, 261, - 262, 263, -1, 265, 266, 267, 268, 269, 284, 285, - 286, 287, 288, 289, -1, -1, 33, -1, -1, -1, - -1, -1, 284, 285, 286, 287, 288, 289, 256, -1, + 270, 271, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 286, 287, 288, 289, + 290, 291, 256, 33, 258, -1, 0, 261, 262, 263, + -1, 265, 266, 267, 268, 269, 270, 271, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 286, 287, 288, 289, 290, 291, 256, 33, + 258, -1, 0, 261, 262, 263, -1, 265, 266, 267, + 268, 269, 270, 271, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 286, 287, + 288, 289, 290, 291, -1, 33, -1, -1, 0, -1, + -1, -1, 256, -1, 258, -1, -1, 261, 262, 263, + -1, 265, 266, 267, 268, 269, 270, 271, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 33, 286, 287, 288, 289, 290, 291, 256, -1, 258, -1, -1, 261, 262, 263, -1, 265, 266, 267, - 268, 269, 256, -1, 258, -1, -1, 261, 262, 263, - -1, 265, 266, 267, 268, 269, 284, 285, 286, 287, - 288, 289, 33, -1, 258, -1, 260, 261, -1, 263, - 284, 285, 286, 287, 288, 289, 256, -1, 258, -1, - -1, 261, 262, 263, -1, 265, 266, 267, 268, 269, - 284, -1, -1, -1, -1, 33, -1, -1, -1, -1, - -1, -1, -1, -1, 284, 285, 286, 287, 288, 289, + 268, 269, 270, 271, 33, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 286, 287, + 288, 289, 290, 291, 256, -1, 258, -1, -1, 261, + 262, 263, -1, 265, 266, 267, 268, 269, 270, 271, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 33, -1, 286, 287, 288, 289, 290, 291, 256, -1, 258, -1, -1, 261, 262, 263, -1, 265, - 266, 267, 268, 269, 33, -1, 258, -1, -1, -1, - -1, 263, -1, -1, -1, -1, -1, -1, 284, 285, - 286, 287, 288, 289, 256, -1, 258, -1, -1, 261, - 262, 263, 284, 265, 266, 267, 268, 269, 256, -1, - 258, -1, -1, 261, 262, 263, -1, 265, 266, 267, - 268, 269, 284, 285, 286, 287, 288, 289, -1, -1, - -1, -1, -1, -1, -1, -1, 284, 285, 286, 287, - 288, 289, 256, -1, 258, -1, -1, 261, 262, 263, - -1, 265, 266, 267, 268, 269, 256, -1, 258, -1, + 266, 267, 268, 269, 270, 271, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 33, -1, -1, -1, -1, + 286, 287, 288, 289, 290, 291, 256, -1, 258, -1, -1, 261, 262, 263, -1, 265, 266, 267, 268, 269, - 284, 285, 286, 287, 288, 289, -1, -1, -1, -1, - -1, -1, -1, -1, 284, 285, 286, 287, 288, 289, - 257, 258, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 270, 271, 272, 273, 274, 275, 276, - 277, 278, 279, 280, 281, 282, 283, 284, -1, -1, - -1, -1, -1, -1, 291, 292, 293, 294, 295, 296, - 297, -1, 299, 300, 301, 302, 257, 258, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 270, - 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, - 281, 282, 283, 284, -1, -1, -1, -1, -1, 257, - 258, -1, -1, -1, -1, -1, -1, -1, 299, 300, - 301, 302, 270, 271, 272, 273, 274, 275, 276, 277, - 278, 279, 280, 281, 282, 283, 284, 256, -1, 258, - -1, -1, 261, 262, 263, -1, 265, 266, 267, 268, - 269, 299, 300, 301, 302, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 284, 285, 286, 287, 288, - 289, + 270, 271, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 286, 287, 288, 289, + 290, 291, 256, -1, 258, 33, -1, 261, 262, 263, + -1, 265, 266, 267, 268, 269, 270, 271, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 286, 287, 288, 289, 290, 291, 256, -1, + 258, -1, -1, 261, 262, 263, -1, 265, 266, 267, + 268, 269, 270, 271, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 286, 287, + 288, 289, 290, 291, 256, -1, 258, -1, -1, 261, + 262, 263, -1, 265, 266, 267, 268, 269, 270, 271, + -1, -1, -1, -1, -1, -1, -1, -1, 257, 258, + -1, -1, -1, -1, 286, 287, 288, 289, 290, 291, + -1, -1, -1, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, -1, -1, + -1, -1, -1, -1, 293, 294, 295, 296, 297, 298, + 299, -1, 301, 302, 303, 304, 257, 258, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, -1, -1, -1, 257, + 258, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 301, 302, 303, 304, 272, 273, 274, 275, 276, 277, + 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 301, 302, 303, 304, -1, 256, -1, + 258, -1, -1, 261, 262, 263, -1, 265, 266, 267, + 268, 269, 270, 271, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 286, 287, + 288, 289, 290, 291, }; -#define YYFINAL 18 +#define YYFINAL 20 #ifndef YYDEBUG #define YYDEBUG 0 #endif -#define YYMAXTOKEN 302 +#define YYMAXTOKEN 304 #if YYDEBUG #if defined(__cplusplus) || defined(__STDC__) const char * const sudoersname[] = @@ -510,12 +553,13 @@ char *sudoersname[] = 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, "COMMAND","ALIAS","DEFVAR","NTWKADDR","NETGROUP","USERGROUP","WORD","DIGEST", -"DEFAULTS","DEFAULTS_HOST","DEFAULTS_USER","DEFAULTS_RUNAS","DEFAULTS_CMND", -"NOPASSWD","PASSWD","NOEXEC","EXEC","SETENV","NOSETENV","LOG_INPUT", -"NOLOG_INPUT","LOG_OUTPUT","NOLOG_OUTPUT","MAIL","NOMAIL","FOLLOWLNK", -"NOFOLLOWLNK","ALL","COMMENT","HOSTALIAS","CMNDALIAS","USERALIAS","RUNASALIAS", -"ERROR","TYPE","ROLE","PRIVS","LIMITPRIVS","CMND_TIMEOUT","NOTBEFORE", -"NOTAFTER","MYSELF","SHA224_TOK","SHA256_TOK","SHA384_TOK","SHA512_TOK", +"INCLUDE","INCLUDEDIR","DEFAULTS","DEFAULTS_HOST","DEFAULTS_USER", +"DEFAULTS_RUNAS","DEFAULTS_CMND","NOPASSWD","PASSWD","NOEXEC","EXEC","SETENV", +"NOSETENV","LOG_INPUT","NOLOG_INPUT","LOG_OUTPUT","NOLOG_OUTPUT","MAIL", +"NOMAIL","FOLLOWLNK","NOFOLLOWLNK","ALL","COMMENT","HOSTALIAS","CMNDALIAS", +"USERALIAS","RUNASALIAS","ERROR","TYPE","ROLE","PRIVS","LIMITPRIVS", +"CMND_TIMEOUT","NOTBEFORE","NOTAFTER","MYSELF","SHA224_TOK","SHA256_TOK", +"SHA384_TOK","SHA512_TOK", }; #if defined(__cplusplus) || defined(__STDC__) const char * const sudoersrule[] = @@ -529,6 +573,8 @@ char *sudoersrule[] = "line : line entry", "entry : COMMENT", "entry : error COMMENT", +"entry : INCLUDE WORD", +"entry : INCLUDEDIR WORD", "entry : userlist privileges", "entry : USERALIAS useraliases", "entry : HOSTALIAS hostaliases", @@ -669,7 +715,7 @@ short *yysslim; YYSTYPE *yyvs; unsigned int yystacksize; int yyparse(void); -#line 917 "gram.y" +#line 933 "gram.y" void sudoerserror(const char *s) { @@ -1119,7 +1165,7 @@ init_options(struct command_options *opts) opts->limitprivs = NULL; #endif } -#line 1065 "gram.c" +#line 1111 "gram.c" /* allocate initial stack or double stack size, up to YYMAXDEPTH */ #if defined(__cplusplus) || defined(__STDC__) static int yygrowstack(void) @@ -1328,23 +1374,43 @@ yyreduce: switch (yyn) { case 1: -#line 171 "gram.y" +#line 173 "gram.y" { ; } break; case 5: -#line 179 "gram.y" +#line 181 "gram.y" { ; } break; case 6: -#line 182 "gram.y" +#line 184 "gram.y" { yyerrok; } break; case 7: -#line 185 "gram.y" +#line 187 "gram.y" +{ + if (!push_include(yyvsp[0].string, false)) { + free(yyvsp[0].string); + YYERROR; + } + free(yyvsp[0].string); + } +break; +case 8: +#line 194 "gram.y" +{ + if (!push_include(yyvsp[0].string, true)) { + free(yyvsp[0].string); + YYERROR; + } + free(yyvsp[0].string); + } +break; +case 9: +#line 201 "gram.y" { if (!add_userspec(yyvsp[-1].member, yyvsp[0].privilege)) { sudoerserror(N_("unable to allocate memory")); @@ -1352,74 +1418,74 @@ case 7: } } break; -case 8: -#line 191 "gram.y" -{ - ; - } -break; -case 9: -#line 194 "gram.y" -{ - ; - } -break; case 10: -#line 197 "gram.y" +#line 207 "gram.y" { ; } break; case 11: -#line 200 "gram.y" +#line 210 "gram.y" { ; } break; case 12: -#line 203 "gram.y" +#line 213 "gram.y" +{ + ; + } +break; +case 13: +#line 216 "gram.y" +{ + ; + } +break; +case 14: +#line 219 "gram.y" { if (!add_defaults(DEFAULTS, NULL, yyvsp[0].defaults)) YYERROR; } break; -case 13: -#line 207 "gram.y" +case 15: +#line 223 "gram.y" { if (!add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; -case 14: -#line 211 "gram.y" +case 16: +#line 227 "gram.y" { if (!add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; -case 15: -#line 215 "gram.y" +case 17: +#line 231 "gram.y" { if (!add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; -case 16: -#line 219 "gram.y" +case 18: +#line 235 "gram.y" { if (!add_defaults(DEFAULTS_CMND, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; -case 18: -#line 226 "gram.y" +case 20: +#line 242 "gram.y" { HLTQ_CONCAT(yyvsp[-2].defaults, yyvsp[0].defaults, entries); yyval.defaults = yyvsp[-2].defaults; } break; -case 19: -#line 232 "gram.y" +case 21: +#line 248 "gram.y" { yyval.defaults = new_default(yyvsp[0].string, NULL, true); if (yyval.defaults == NULL) { @@ -1428,8 +1494,8 @@ case 19: } } break; -case 20: -#line 239 "gram.y" +case 22: +#line 255 "gram.y" { yyval.defaults = new_default(yyvsp[0].string, NULL, false); if (yyval.defaults == NULL) { @@ -1438,8 +1504,8 @@ case 20: } } break; -case 21: -#line 246 "gram.y" +case 23: +#line 262 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, true); if (yyval.defaults == NULL) { @@ -1448,8 +1514,8 @@ case 21: } } break; -case 22: -#line 253 "gram.y" +case 24: +#line 269 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '+'); if (yyval.defaults == NULL) { @@ -1458,8 +1524,8 @@ case 22: } } break; -case 23: -#line 260 "gram.y" +case 25: +#line 276 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '-'); if (yyval.defaults == NULL) { @@ -1468,15 +1534,15 @@ case 23: } } break; -case 25: -#line 270 "gram.y" +case 27: +#line 286 "gram.y" { HLTQ_CONCAT(yyvsp[-2].privilege, yyvsp[0].privilege, entries); yyval.privilege = yyvsp[-2].privilege; } break; -case 26: -#line 276 "gram.y" +case 28: +#line 292 "gram.y" { struct privilege *p = calloc(1, sizeof(*p)); if (p == NULL) { @@ -1490,22 +1556,22 @@ case 26: yyval.privilege = p; } break; -case 27: -#line 290 "gram.y" +case 29: +#line 306 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; -case 28: -#line 294 "gram.y" +case 30: +#line 310 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; -case 29: -#line 300 "gram.y" +case 31: +#line 316 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -1514,8 +1580,8 @@ case 29: } } break; -case 30: -#line 307 "gram.y" +case 32: +#line 323 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -1524,8 +1590,8 @@ case 30: } } break; -case 31: -#line 314 "gram.y" +case 33: +#line 330 "gram.y" { yyval.member = new_member(yyvsp[0].string, NETGROUP); if (yyval.member == NULL) { @@ -1534,8 +1600,8 @@ case 31: } } break; -case 32: -#line 321 "gram.y" +case 34: +#line 337 "gram.y" { yyval.member = new_member(yyvsp[0].string, NTWKADDR); if (yyval.member == NULL) { @@ -1544,8 +1610,8 @@ case 32: } } break; -case 33: -#line 328 "gram.y" +case 35: +#line 344 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); if (yyval.member == NULL) { @@ -1554,8 +1620,8 @@ case 33: } } break; -case 35: -#line 338 "gram.y" +case 37: +#line 354 "gram.y" { struct cmndspec *prev; prev = HLTQ_LAST(yyvsp[-2].cmndspec, cmndspec, entries); @@ -1608,8 +1674,8 @@ case 35: yyval.cmndspec = yyvsp[-2].cmndspec; } break; -case 36: -#line 391 "gram.y" +case 38: +#line 407 "gram.y" { struct cmndspec *cs = calloc(1, sizeof(*cs)); if (cs == NULL) { @@ -1662,8 +1728,8 @@ case 36: yyval.cmndspec = cs; } break; -case 37: -#line 444 "gram.y" +case 39: +#line 460 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA224, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1672,8 +1738,8 @@ case 37: } } break; -case 38: -#line 451 "gram.y" +case 40: +#line 467 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA256, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1682,8 +1748,8 @@ case 38: } } break; -case 39: -#line 458 "gram.y" +case 41: +#line 474 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA384, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1692,8 +1758,8 @@ case 39: } } break; -case 40: -#line 465 "gram.y" +case 42: +#line 481 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA512, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1702,21 +1768,21 @@ case 40: } } break; -case 42: -#line 475 "gram.y" +case 44: +#line 491 "gram.y" { HLTQ_CONCAT(yyvsp[-2].digest, yyvsp[0].digest, entries); yyval.digest = yyvsp[-2].digest; } break; -case 43: -#line 481 "gram.y" +case 45: +#line 497 "gram.y" { yyval.member = yyvsp[0].member; } break; -case 44: -#line 484 "gram.y" +case 46: +#line 500 "gram.y" { struct sudo_command *c = (struct sudo_command *) yyvsp[0].member->name; @@ -1737,76 +1803,76 @@ case 44: yyval.member = yyvsp[0].member; } break; -case 45: -#line 505 "gram.y" +case 47: +#line 521 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; -case 46: -#line 509 "gram.y" +case 48: +#line 525 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; -case 47: -#line 515 "gram.y" -{ - yyval.string = yyvsp[0].string; - } -break; -case 48: -#line 520 "gram.y" -{ - yyval.string = yyvsp[0].string; - } -break; case 49: -#line 524 "gram.y" +#line 531 "gram.y" { yyval.string = yyvsp[0].string; } break; case 50: -#line 529 "gram.y" +#line 536 "gram.y" { yyval.string = yyvsp[0].string; } break; case 51: -#line 534 "gram.y" +#line 540 "gram.y" { yyval.string = yyvsp[0].string; } break; case 52: -#line 539 "gram.y" +#line 545 "gram.y" { yyval.string = yyvsp[0].string; } break; case 53: -#line 543 "gram.y" +#line 550 "gram.y" { yyval.string = yyvsp[0].string; } break; case 54: -#line 548 "gram.y" +#line 555 "gram.y" +{ + yyval.string = yyvsp[0].string; + } +break; +case 55: +#line 559 "gram.y" +{ + yyval.string = yyvsp[0].string; + } +break; +case 56: +#line 564 "gram.y" { yyval.runas = NULL; } break; -case 55: -#line 551 "gram.y" +case 57: +#line 567 "gram.y" { yyval.runas = yyvsp[-1].runas; } break; -case 56: -#line 556 "gram.y" +case 58: +#line 572 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas != NULL) { @@ -1823,8 +1889,8 @@ case 56: } } break; -case 57: -#line 571 "gram.y" +case 59: +#line 587 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas == NULL) { @@ -1835,8 +1901,8 @@ case 57: /* $$->runasgroups = NULL; */ } break; -case 58: -#line 580 "gram.y" +case 60: +#line 596 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas == NULL) { @@ -1847,8 +1913,8 @@ case 58: yyval.runas->runasgroups = yyvsp[0].member; } break; -case 59: -#line 589 "gram.y" +case 61: +#line 605 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas == NULL) { @@ -1859,8 +1925,8 @@ case 59: yyval.runas->runasgroups = yyvsp[0].member; } break; -case 60: -#line 598 "gram.y" +case 62: +#line 614 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas != NULL) { @@ -1877,14 +1943,14 @@ case 60: } } break; -case 61: -#line 615 "gram.y" +case 63: +#line 631 "gram.y" { init_options(&yyval.options); } break; -case 62: -#line 618 "gram.y" +case 64: +#line 634 "gram.y" { yyval.options.notbefore = parse_gentime(yyvsp[0].string); free(yyvsp[0].string); @@ -1894,8 +1960,8 @@ case 62: } } break; -case 63: -#line 626 "gram.y" +case 65: +#line 642 "gram.y" { yyval.options.notafter = parse_gentime(yyvsp[0].string); free(yyvsp[0].string); @@ -1905,8 +1971,8 @@ case 63: } } break; -case 64: -#line 634 "gram.y" +case 66: +#line 650 "gram.y" { yyval.options.timeout = parse_timeout(yyvsp[0].string); free(yyvsp[0].string); @@ -1919,8 +1985,8 @@ case 64: } } break; -case 65: -#line 645 "gram.y" +case 67: +#line 661 "gram.y" { #ifdef HAVE_SELINUX free(yyval.options.role); @@ -1928,8 +1994,8 @@ case 65: #endif } break; -case 66: -#line 651 "gram.y" +case 68: +#line 667 "gram.y" { #ifdef HAVE_SELINUX free(yyval.options.type); @@ -1937,8 +2003,8 @@ case 66: #endif } break; -case 67: -#line 657 "gram.y" +case 69: +#line 673 "gram.y" { #ifdef HAVE_PRIV_SET free(yyval.options.privs); @@ -1946,8 +2012,8 @@ case 67: #endif } break; -case 68: -#line 663 "gram.y" +case 70: +#line 679 "gram.y" { #ifdef HAVE_PRIV_SET free(yyval.options.limitprivs); @@ -1955,98 +2021,98 @@ case 68: #endif } break; -case 69: -#line 671 "gram.y" +case 71: +#line 687 "gram.y" { TAGS_INIT(yyval.tag); } break; -case 70: -#line 674 "gram.y" +case 72: +#line 690 "gram.y" { yyval.tag.nopasswd = true; } break; -case 71: -#line 677 "gram.y" +case 73: +#line 693 "gram.y" { yyval.tag.nopasswd = false; } break; -case 72: -#line 680 "gram.y" +case 74: +#line 696 "gram.y" { yyval.tag.noexec = true; } break; -case 73: -#line 683 "gram.y" +case 75: +#line 699 "gram.y" { yyval.tag.noexec = false; } break; -case 74: -#line 686 "gram.y" +case 76: +#line 702 "gram.y" { yyval.tag.setenv = true; } break; -case 75: -#line 689 "gram.y" +case 77: +#line 705 "gram.y" { yyval.tag.setenv = false; } break; -case 76: -#line 692 "gram.y" +case 78: +#line 708 "gram.y" { yyval.tag.log_input = true; } break; -case 77: -#line 695 "gram.y" +case 79: +#line 711 "gram.y" { yyval.tag.log_input = false; } break; -case 78: -#line 698 "gram.y" +case 80: +#line 714 "gram.y" { yyval.tag.log_output = true; } break; -case 79: -#line 701 "gram.y" +case 81: +#line 717 "gram.y" { yyval.tag.log_output = false; } break; -case 80: -#line 704 "gram.y" +case 82: +#line 720 "gram.y" { yyval.tag.follow = true; } break; -case 81: -#line 707 "gram.y" +case 83: +#line 723 "gram.y" { yyval.tag.follow = false; } break; -case 82: -#line 710 "gram.y" +case 84: +#line 726 "gram.y" { yyval.tag.send_mail = true; } break; -case 83: -#line 713 "gram.y" +case 85: +#line 729 "gram.y" { yyval.tag.send_mail = false; } break; -case 84: -#line 718 "gram.y" +case 86: +#line 734 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -2055,8 +2121,8 @@ case 84: } } break; -case 85: -#line 725 "gram.y" +case 87: +#line 741 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -2065,8 +2131,8 @@ case 85: } } break; -case 86: -#line 732 "gram.y" +case 88: +#line 748 "gram.y" { struct sudo_command *c; @@ -2082,8 +2148,8 @@ case 86: } } break; -case 89: -#line 752 "gram.y" +case 91: +#line 768 "gram.y" { const char *s; s = alias_add(&parsed_policy, yyvsp[-2].string, HOSTALIAS, @@ -2094,15 +2160,15 @@ case 89: } } break; -case 91: -#line 764 "gram.y" +case 93: +#line 780 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; -case 94: -#line 774 "gram.y" +case 96: +#line 790 "gram.y" { const char *s; s = alias_add(&parsed_policy, yyvsp[-2].string, CMNDALIAS, @@ -2113,15 +2179,15 @@ case 94: } } break; -case 96: -#line 786 "gram.y" +case 98: +#line 802 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; -case 99: -#line 796 "gram.y" +case 101: +#line 812 "gram.y" { const char *s; s = alias_add(&parsed_policy, yyvsp[-2].string, RUNASALIAS, @@ -2132,8 +2198,8 @@ case 99: } } break; -case 102: -#line 811 "gram.y" +case 104: +#line 827 "gram.y" { const char *s; s = alias_add(&parsed_policy, yyvsp[-2].string, USERALIAS, @@ -2144,29 +2210,29 @@ case 102: } } break; -case 104: -#line 823 "gram.y" +case 106: +#line 839 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; -case 105: -#line 829 "gram.y" +case 107: +#line 845 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; -case 106: -#line 833 "gram.y" +case 108: +#line 849 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; -case 107: -#line 839 "gram.y" +case 109: +#line 855 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -2175,8 +2241,8 @@ case 107: } } break; -case 108: -#line 846 "gram.y" +case 110: +#line 862 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -2185,8 +2251,8 @@ case 108: } } break; -case 109: -#line 853 "gram.y" +case 111: +#line 869 "gram.y" { yyval.member = new_member(yyvsp[0].string, NETGROUP); if (yyval.member == NULL) { @@ -2195,8 +2261,8 @@ case 109: } } break; -case 110: -#line 860 "gram.y" +case 112: +#line 876 "gram.y" { yyval.member = new_member(yyvsp[0].string, USERGROUP); if (yyval.member == NULL) { @@ -2205,8 +2271,8 @@ case 110: } } break; -case 111: -#line 867 "gram.y" +case 113: +#line 883 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); if (yyval.member == NULL) { @@ -2215,29 +2281,29 @@ case 111: } } break; -case 113: -#line 877 "gram.y" +case 115: +#line 893 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; -case 114: -#line 883 "gram.y" +case 116: +#line 899 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; -case 115: -#line 887 "gram.y" +case 117: +#line 903 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; -case 116: -#line 893 "gram.y" +case 118: +#line 909 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -2246,8 +2312,8 @@ case 116: } } break; -case 117: -#line 900 "gram.y" +case 119: +#line 916 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -2256,8 +2322,8 @@ case 117: } } break; -case 118: -#line 907 "gram.y" +case 120: +#line 923 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); if (yyval.member == NULL) { @@ -2266,7 +2332,7 @@ case 118: } } break; -#line 2212 "gram.c" +#line 2278 "gram.c" } yyssp -= yym; yystate = *yyssp; diff --git a/plugins/sudoers/gram.h b/plugins/sudoers/gram.h index dc8f347e0..0283daa68 100644 --- a/plugins/sudoers/gram.h +++ b/plugins/sudoers/gram.h @@ -6,44 +6,46 @@ #define USERGROUP 262 #define WORD 263 #define DIGEST 264 -#define DEFAULTS 265 -#define DEFAULTS_HOST 266 -#define DEFAULTS_USER 267 -#define DEFAULTS_RUNAS 268 -#define DEFAULTS_CMND 269 -#define NOPASSWD 270 -#define PASSWD 271 -#define NOEXEC 272 -#define EXEC 273 -#define SETENV 274 -#define NOSETENV 275 -#define LOG_INPUT 276 -#define NOLOG_INPUT 277 -#define LOG_OUTPUT 278 -#define NOLOG_OUTPUT 279 -#define MAIL 280 -#define NOMAIL 281 -#define FOLLOWLNK 282 -#define NOFOLLOWLNK 283 -#define ALL 284 -#define COMMENT 285 -#define HOSTALIAS 286 -#define CMNDALIAS 287 -#define USERALIAS 288 -#define RUNASALIAS 289 -#define ERROR 290 -#define TYPE 291 -#define ROLE 292 -#define PRIVS 293 -#define LIMITPRIVS 294 -#define CMND_TIMEOUT 295 -#define NOTBEFORE 296 -#define NOTAFTER 297 -#define MYSELF 298 -#define SHA224_TOK 299 -#define SHA256_TOK 300 -#define SHA384_TOK 301 -#define SHA512_TOK 302 +#define INCLUDE 265 +#define INCLUDEDIR 266 +#define DEFAULTS 267 +#define DEFAULTS_HOST 268 +#define DEFAULTS_USER 269 +#define DEFAULTS_RUNAS 270 +#define DEFAULTS_CMND 271 +#define NOPASSWD 272 +#define PASSWD 273 +#define NOEXEC 274 +#define EXEC 275 +#define SETENV 276 +#define NOSETENV 277 +#define LOG_INPUT 278 +#define NOLOG_INPUT 279 +#define LOG_OUTPUT 280 +#define NOLOG_OUTPUT 281 +#define MAIL 282 +#define NOMAIL 283 +#define FOLLOWLNK 284 +#define NOFOLLOWLNK 285 +#define ALL 286 +#define COMMENT 287 +#define HOSTALIAS 288 +#define CMNDALIAS 289 +#define USERALIAS 290 +#define RUNASALIAS 291 +#define ERROR 292 +#define TYPE 293 +#define ROLE 294 +#define PRIVS 295 +#define LIMITPRIVS 296 +#define CMND_TIMEOUT 297 +#define NOTBEFORE 298 +#define NOTAFTER 299 +#define MYSELF 300 +#define SHA224_TOK 301 +#define SHA256_TOK 302 +#define SHA384_TOK 303 +#define SHA512_TOK 304 #ifndef YYSTYPE_DEFINED #define YYSTYPE_DEFINED typedef union { diff --git a/plugins/sudoers/gram.y b/plugins/sudoers/gram.y index 369340560..60702a15f 100644 --- a/plugins/sudoers/gram.y +++ b/plugins/sudoers/gram.y @@ -92,6 +92,8 @@ static struct command_digest *new_digest(int, char *); %token USERGROUP /* a usergroup (%NAME) */ %token WORD /* a word */ %token DIGEST /* a SHA-2 digest */ +%token INCLUDE /* @include */ +%token INCLUDEDIR /* @includedir */ %token DEFAULTS /* Defaults entry */ %token DEFAULTS_HOST /* Host-specific defaults entry */ %token DEFAULTS_USER /* User-specific defaults entry */ @@ -182,6 +184,20 @@ entry : COMMENT { | error COMMENT { yyerrok; } + | INCLUDE WORD { + if (!push_include($2, false)) { + free($2); + YYERROR; + } + free($2); + } + | INCLUDEDIR WORD { + if (!push_include($2, true)) { + free($2); + YYERROR; + } + free($2); + } | userlist privileges { if (!add_userspec($1, $2)) { sudoerserror(N_("unable to allocate memory")); diff --git a/plugins/sudoers/regress/testsudoers/test10.out.ok b/plugins/sudoers/regress/testsudoers/test10.out.ok new file mode 100644 index 000000000..5a1a68ad8 --- /dev/null +++ b/plugins/sudoers/regress/testsudoers/test10.out.ok @@ -0,0 +1,51 @@ +Testing @include of a path with escaped white space + +Parses OK. + +Entries for user root: + +ALL = ALL + host matched + runas matched + cmnd allowed + +Command allowed + +Testing @include of a double-quoted path with white space + +Parses OK. + +Entries for user root: + +ALL = ALL + host matched + runas matched + cmnd allowed + +Command allowed + +Testing #include of a path with escaped white space + +Parses OK. + +Entries for user root: + +ALL = ALL + host matched + runas matched + cmnd allowed + +Command allowed + +Testing #include of a double-quoted path with white space + +Parses OK. + +Entries for user root: + +ALL = ALL + host matched + runas matched + cmnd allowed + +Command allowed diff --git a/plugins/sudoers/regress/testsudoers/test10.sh b/plugins/sudoers/regress/testsudoers/test10.sh new file mode 100755 index 000000000..2529ad2fa --- /dev/null +++ b/plugins/sudoers/regress/testsudoers/test10.sh @@ -0,0 +1,44 @@ +#!/bin/sh +# +# Test @include of a file with embedded white space +# + +# Create test file +TESTDIR="`pwd`/regress/testsudoers" +cat >"$TESTDIR/test 10.inc" <&1 + +echo "Testing @include of a path with escaped white space" +echo "" +./testsudoers -U $MYUID -G $MYGID root id <<-EOF + @include $TESTDIR/test\ 10.inc +EOF + +echo "" +echo "Testing @include of a double-quoted path with white space" +echo "" +./testsudoers -U $MYUID -G $MYGID root id <<-EOF + @include "$TESTDIR/test 10.inc" +EOF + +echo "" +echo "Testing #include of a path with escaped white space" +echo "" +./testsudoers -U $MYUID -G $MYGID root id <<-EOF + #include $TESTDIR/test\ 10.inc +EOF + +echo "" +echo "Testing #include of a double-quoted path with white space" +echo "" +./testsudoers -U $MYUID -G $MYGID root id <<-EOF + #include "$TESTDIR/test 10.inc" +EOF + +rm -f "$TESTDIR/test 10.inc" +exit 0 diff --git a/plugins/sudoers/regress/testsudoers/test11.out.ok b/plugins/sudoers/regress/testsudoers/test11.out.ok new file mode 100644 index 000000000..e7f2c8abf --- /dev/null +++ b/plugins/sudoers/regress/testsudoers/test11.out.ok @@ -0,0 +1,27 @@ +Testing @include with garbage after the path name + +>>> sudoers: syntax error near line 1 <<< +Parse error in sudoers near line 1. + +Entries for user root: + +ALL = ALL + host matched + runas matched + cmnd allowed + +Command allowed + +Testing #include with garbage after the path name + +>>> sudoers: syntax error near line 1 <<< +Parse error in sudoers near line 1. + +Entries for user root: + +ALL = ALL + host matched + runas matched + cmnd allowed + +Command allowed diff --git a/plugins/sudoers/regress/testsudoers/test11.sh b/plugins/sudoers/regress/testsudoers/test11.sh new file mode 100755 index 000000000..5a7089670 --- /dev/null +++ b/plugins/sudoers/regress/testsudoers/test11.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# +# Test @include with garbage after the path name +# + +# Avoid warnings about memory leaks when there is a syntax error +ASAN_OPTIONS=detect_leaks=0; export ASAN_OPTIONS + +MYUID=`\ls -ln $TESTDIR/test2.inc | awk '{print $3}'` +MYGID=`\ls -ln $TESTDIR/test2.inc | awk '{print $4}'` +exec 2>&1 + +echo "Testing @include with garbage after the path name" +echo "" +./testsudoers -U $MYUID -G $MYGID root id <&1 + +echo "Testing @include" +echo "" +./testsudoers -U $MYUID -G $MYGID root id <&1 + + echo "Testing @includedir of an unquoted path" + echo "" + ./testsudoers -U $MYUID -G $MYGID root id <<-EOF + @includedir $TESTDIR/test3.d + EOF + + echo "" + echo "Testing @includedir of a double-quoted path" + echo "" + ./testsudoers -U $MYUID -G $MYGID root id <<-EOF + @includedir "$TESTDIR/test3.d" + EOF + + echo "" + echo "Testing #includedir of an unquoted path" + echo "" ./testsudoers -U $MYUID -G $MYGID root id <<-EOF #includedir $TESTDIR/test3.d EOF + + echo "" + echo "Testing #includedir of a double-quoted path" + echo "" + ./testsudoers -U $MYUID -G $MYGID root id <<-EOF + #includedir "$TESTDIR/test3.d" + EOF + + rm -rf "${parentdir}/test3.d" exit 0 fi diff --git a/plugins/sudoers/regress/testsudoers/test4.sh b/plugins/sudoers/regress/testsudoers/test4.sh index 3eaaa1dac..e659a9a2b 100755 --- a/plugins/sudoers/regress/testsudoers/test4.sh +++ b/plugins/sudoers/regress/testsudoers/test4.sh @@ -8,7 +8,7 @@ ASAN_OPTIONS=detect_leaks=0; export ASAN_OPTIONS exec 2>&1 ./testsudoers -U 1 root id <&1 # Test world writable chmod 666 $TESTFILE ./testsudoers -U $MYUID -G $MYGID root id <&1 + +echo "Testing @include without a newline" +echo "" +printf "@include $TESTDIR/test2.inc" | \ + ./testsudoers -U $MYUID -G $MYGID root id + +echo "" +echo "Testing #include without a newline" +echo "" printf "#include $TESTDIR/test2.inc" | \ ./testsudoers -U $MYUID -G $MYGID root id diff --git a/plugins/sudoers/regress/testsudoers/test9.out.ok b/plugins/sudoers/regress/testsudoers/test9.out.ok new file mode 100644 index 000000000..eabeb20e7 --- /dev/null +++ b/plugins/sudoers/regress/testsudoers/test9.out.ok @@ -0,0 +1,10 @@ +Parses OK. + +Entries for user root: + +ALL = ALL + host matched + runas matched + cmnd allowed + +Command allowed diff --git a/plugins/sudoers/regress/testsudoers/test9.sh b/plugins/sudoers/regress/testsudoers/test9.sh new file mode 100755 index 000000000..d76cfbbe3 --- /dev/null +++ b/plugins/sudoers/regress/testsudoers/test9.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# +# Test #include facility +# + +MYUID=`\ls -ln $TESTDIR/test2.inc | awk '{print $3}'` +MYGID=`\ls -ln $TESTDIR/test2.inc | awk '{print $4}'` +exec 2>&1 +./testsudoers -U $MYUID -G $MYGID root id <= 896 ) + if ( yy_current_state >= 916 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 6175 ); + while ( yy_base[yy_current_state] != 6090 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -2546,7 +2521,7 @@ do_action: /* This label is used only to access EOF actions. */ case 1: YY_RULE_SETUP -#line 111 "toke.l" +#line 105 "toke.l" { LEXTRACE(", "); LEXRETURN(','); @@ -2554,12 +2529,12 @@ YY_RULE_SETUP YY_BREAK case 2: YY_RULE_SETUP -#line 116 "toke.l" +#line 110 "toke.l" BEGIN STARTDEFS; YY_BREAK case 3: YY_RULE_SETUP -#line 118 "toke.l" +#line 112 "toke.l" { BEGIN INDEFS; LEXTRACE("DEFVAR "); @@ -2571,7 +2546,7 @@ YY_RULE_SETUP case 4: YY_RULE_SETUP -#line 127 "toke.l" +#line 121 "toke.l" { BEGIN STARTDEFS; LEXTRACE(", "); @@ -2580,7 +2555,7 @@ YY_RULE_SETUP YY_BREAK case 5: YY_RULE_SETUP -#line 133 "toke.l" +#line 127 "toke.l" { LEXTRACE("= "); LEXRETURN('='); @@ -2588,7 +2563,7 @@ YY_RULE_SETUP YY_BREAK case 6: YY_RULE_SETUP -#line 138 "toke.l" +#line 132 "toke.l" { LEXTRACE("+= "); LEXRETURN('+'); @@ -2596,7 +2571,7 @@ YY_RULE_SETUP YY_BREAK case 7: YY_RULE_SETUP -#line 143 "toke.l" +#line 137 "toke.l" { LEXTRACE("-= "); LEXRETURN('-'); @@ -2604,7 +2579,7 @@ YY_RULE_SETUP YY_BREAK case 8: YY_RULE_SETUP -#line 148 "toke.l" +#line 142 "toke.l" { LEXTRACE("BEGINSTR "); sudoerslval.string = NULL; @@ -2614,7 +2589,7 @@ YY_RULE_SETUP YY_BREAK case 9: YY_RULE_SETUP -#line 155 "toke.l" +#line 149 "toke.l" { LEXTRACE("WORD(2) "); if (!fill(sudoerstext, sudoersleng)) @@ -2627,7 +2602,7 @@ YY_RULE_SETUP case 10: /* rule 10 can match eol */ YY_RULE_SETUP -#line 164 "toke.l" +#line 158 "toke.l" { /* Line continuation char followed by newline. */ sudolineno++; @@ -2636,7 +2611,7 @@ YY_RULE_SETUP YY_BREAK case 11: YY_RULE_SETUP -#line 170 "toke.l" +#line 164 "toke.l" { LEXTRACE("ENDSTR "); BEGIN prev_state; @@ -2671,7 +2646,7 @@ YY_RULE_SETUP YY_BREAK case 12: YY_RULE_SETUP -#line 202 "toke.l" +#line 196 "toke.l" { LEXTRACE("BACKSLASH "); if (!append(sudoerstext, sudoersleng)) @@ -2680,7 +2655,7 @@ YY_RULE_SETUP YY_BREAK case 13: YY_RULE_SETUP -#line 208 "toke.l" +#line 202 "toke.l" { LEXTRACE("STRBODY "); if (!append(sudoerstext, sudoersleng)) @@ -2691,7 +2666,7 @@ YY_RULE_SETUP case 14: YY_RULE_SETUP -#line 216 "toke.l" +#line 210 "toke.l" { /* quoted fnmatch glob char, pass verbatim */ LEXTRACE("QUOTEDCHAR "); @@ -2702,7 +2677,7 @@ YY_RULE_SETUP YY_BREAK case 15: YY_RULE_SETUP -#line 224 "toke.l" +#line 218 "toke.l" { /* quoted sudoers special char, strip backslash */ LEXTRACE("QUOTEDCHAR "); @@ -2714,7 +2689,7 @@ YY_RULE_SETUP case 16: /* rule 16 can match eol */ YY_RULE_SETUP -#line 232 "toke.l" +#line 226 "toke.l" { BEGIN INITIAL; yyless(0); @@ -2723,7 +2698,7 @@ YY_RULE_SETUP YY_BREAK case 17: YY_RULE_SETUP -#line 238 "toke.l" +#line 232 "toke.l" { LEXTRACE("ARG "); if (!fill_args(sudoerstext, sudoersleng, sawspace)) @@ -2734,7 +2709,7 @@ YY_RULE_SETUP case 18: YY_RULE_SETUP -#line 246 "toke.l" +#line 240 "toke.l" { /* Only return DIGEST if the length is correct. */ yy_size_t digest_len = @@ -2752,7 +2727,7 @@ YY_RULE_SETUP YY_BREAK case 19: YY_RULE_SETUP -#line 261 "toke.l" +#line 255 "toke.l" { /* Only return DIGEST if the length is correct. */ yy_size_t len, digest_len = @@ -2776,55 +2751,72 @@ YY_RULE_SETUP } /* base64 digest */ YY_BREAK case 20: -/* rule 20 can match eol */ YY_RULE_SETUP -#line 283 "toke.l" +#line 277 "toke.l" { - char *path; - if (continued) { LEXTRACE("ERROR "); LEXRETURN(ERROR); } - if ((path = parse_include(sudoerstext)) == NULL) - yyterminate(); - - LEXTRACE("INCLUDE\n"); - - /* Push current buffer and switch to include file */ - if (!push_include(path)) - yyterminate(); + BEGIN GOTINC; + LEXTRACE("INCLUDE "); + LEXRETURN(INCLUDE); } YY_BREAK case 21: -/* rule 21 can match eol */ YY_RULE_SETUP -#line 301 "toke.l" +#line 288 "toke.l" { - char *path; - if (continued) { LEXTRACE("ERROR "); LEXRETURN(ERROR); } - if ((path = parse_includedir(sudoerstext)) == NULL) - yyterminate(); - - LEXTRACE("INCLUDEDIR\n"); - - /* - * Push current buffer and switch to include file, - * ignoring missing or empty directories. - */ - if (!push_includedir(path)) - yyterminate(); + BEGIN GOTINC; + LEXTRACE("INCLUDEDIR "); + LEXRETURN(INCLUDEDIR); } YY_BREAK case 22: +/* rule 22 can match eol */ YY_RULE_SETUP -#line 322 "toke.l" +#line 299 "toke.l" +{ + if (continued) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + + /* only consume #include */ + yyless(sizeof("#include") - 1); + + BEGIN GOTINC; + LEXTRACE("INCLUDE "); + LEXRETURN(INCLUDE); + } + YY_BREAK +case 23: +/* rule 23 can match eol */ +YY_RULE_SETUP +#line 313 "toke.l" +{ + if (continued) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + + /* only consume #includedir */ + yyless(sizeof("#includedir") - 1); + + BEGIN GOTINC; + LEXTRACE("INCLUDEDIR "); + LEXRETURN(INCLUDEDIR); + } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 327 "toke.l" { char deftype; int n; @@ -2865,9 +2857,9 @@ YY_RULE_SETUP } } YY_BREAK -case 23: +case 25: YY_RULE_SETUP -#line 362 "toke.l" +#line 367 "toke.l" { int n; @@ -2894,132 +2886,132 @@ YY_RULE_SETUP } } YY_BREAK -case 24: +case 26: YY_RULE_SETUP -#line 388 "toke.l" +#line 393 "toke.l" { /* cmnd does not require passwd for this user */ LEXTRACE("NOPASSWD "); LEXRETURN(NOPASSWD); } YY_BREAK -case 25: +case 27: YY_RULE_SETUP -#line 394 "toke.l" +#line 399 "toke.l" { /* cmnd requires passwd for this user */ LEXTRACE("PASSWD "); LEXRETURN(PASSWD); } YY_BREAK -case 26: +case 28: YY_RULE_SETUP -#line 400 "toke.l" +#line 405 "toke.l" { LEXTRACE("NOEXEC "); LEXRETURN(NOEXEC); } YY_BREAK -case 27: +case 29: YY_RULE_SETUP -#line 405 "toke.l" +#line 410 "toke.l" { LEXTRACE("EXEC "); LEXRETURN(EXEC); } YY_BREAK -case 28: +case 30: YY_RULE_SETUP -#line 410 "toke.l" +#line 415 "toke.l" { LEXTRACE("SETENV "); LEXRETURN(SETENV); } YY_BREAK -case 29: +case 31: YY_RULE_SETUP -#line 415 "toke.l" +#line 420 "toke.l" { LEXTRACE("NOSETENV "); LEXRETURN(NOSETENV); } YY_BREAK -case 30: +case 32: YY_RULE_SETUP -#line 420 "toke.l" +#line 425 "toke.l" { LEXTRACE("LOG_OUTPUT "); LEXRETURN(LOG_OUTPUT); } YY_BREAK -case 31: +case 33: YY_RULE_SETUP -#line 425 "toke.l" +#line 430 "toke.l" { LEXTRACE("NOLOG_OUTPUT "); LEXRETURN(NOLOG_OUTPUT); } YY_BREAK -case 32: +case 34: YY_RULE_SETUP -#line 430 "toke.l" +#line 435 "toke.l" { LEXTRACE("LOG_INPUT "); LEXRETURN(LOG_INPUT); } YY_BREAK -case 33: +case 35: YY_RULE_SETUP -#line 435 "toke.l" +#line 440 "toke.l" { LEXTRACE("NOLOG_INPUT "); LEXRETURN(NOLOG_INPUT); } YY_BREAK -case 34: +case 36: YY_RULE_SETUP -#line 440 "toke.l" +#line 445 "toke.l" { LEXTRACE("MAIL "); LEXRETURN(MAIL); } YY_BREAK -case 35: +case 37: YY_RULE_SETUP -#line 445 "toke.l" +#line 450 "toke.l" { LEXTRACE("NOMAIL "); LEXRETURN(NOMAIL); } YY_BREAK -case 36: +case 38: YY_RULE_SETUP -#line 450 "toke.l" +#line 455 "toke.l" { LEXTRACE("FOLLOW "); LEXRETURN(FOLLOWLNK); } YY_BREAK -case 37: +case 39: YY_RULE_SETUP -#line 455 "toke.l" +#line 460 "toke.l" { LEXTRACE("NOFOLLOW "); LEXRETURN(NOFOLLOWLNK); } YY_BREAK -case 38: +case 40: YY_RULE_SETUP -#line 460 "toke.l" +#line 465 "toke.l" { /* empty group or netgroup */ LEXTRACE("ERROR "); LEXRETURN(ERROR); } YY_BREAK -case 39: +case 41: YY_RULE_SETUP -#line 466 "toke.l" +#line 471 "toke.l" { /* netgroup */ if (!fill(sudoerstext, sudoersleng)) @@ -3028,9 +3020,9 @@ YY_RULE_SETUP LEXRETURN(NETGROUP); } YY_BREAK -case 40: +case 42: YY_RULE_SETUP -#line 474 "toke.l" +#line 479 "toke.l" { /* group */ if (!fill(sudoerstext, sudoersleng)) @@ -3039,34 +3031,10 @@ YY_RULE_SETUP LEXRETURN(USERGROUP); } YY_BREAK -case 41: -YY_RULE_SETUP -#line 482 "toke.l" -{ - if (!fill(sudoerstext, sudoersleng)) - yyterminate(); - LEXTRACE("NTWKADDR "); - LEXRETURN(NTWKADDR); - } - YY_BREAK -case 42: -YY_RULE_SETUP -#line 489 "toke.l" -{ - if (!fill(sudoerstext, sudoersleng)) - yyterminate(); - LEXTRACE("NTWKADDR "); - LEXRETURN(NTWKADDR); - } - YY_BREAK case 43: YY_RULE_SETUP -#line 496 "toke.l" +#line 487 "toke.l" { - if (!ipv6_valid(sudoerstext)) { - LEXTRACE("ERROR "); - LEXRETURN(ERROR); - } if (!fill(sudoerstext, sudoersleng)) yyterminate(); LEXTRACE("NTWKADDR "); @@ -3075,7 +3043,17 @@ YY_RULE_SETUP YY_BREAK case 44: YY_RULE_SETUP -#line 507 "toke.l" +#line 494 "toke.l" +{ + if (!fill(sudoerstext, sudoersleng)) + yyterminate(); + LEXTRACE("NTWKADDR "); + LEXRETURN(NTWKADDR); + } + YY_BREAK +case 45: +YY_RULE_SETUP +#line 501 "toke.l" { if (!ipv6_valid(sudoerstext)) { LEXTRACE("ERROR "); @@ -3087,42 +3065,56 @@ YY_RULE_SETUP LEXRETURN(NTWKADDR); } YY_BREAK -case 45: +case 46: YY_RULE_SETUP -#line 518 "toke.l" +#line 512 "toke.l" +{ + if (!ipv6_valid(sudoerstext)) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + if (!fill(sudoerstext, sudoersleng)) + yyterminate(); + LEXTRACE("NTWKADDR "); + LEXRETURN(NTWKADDR); + } + YY_BREAK +case 47: +YY_RULE_SETUP +#line 523 "toke.l" { LEXTRACE("ALL "); LEXRETURN(ALL); } YY_BREAK -case 46: +case 48: YY_RULE_SETUP -#line 524 "toke.l" +#line 529 "toke.l" { LEXTRACE("CMND_TIMEOUT "); LEXRETURN(CMND_TIMEOUT); } YY_BREAK -case 47: +case 49: YY_RULE_SETUP -#line 529 "toke.l" +#line 534 "toke.l" { LEXTRACE("NOTBEFORE "); LEXRETURN(NOTBEFORE); } YY_BREAK -case 48: +case 50: YY_RULE_SETUP -#line 534 "toke.l" +#line 539 "toke.l" { LEXTRACE("NOTAFTER "); LEXRETURN(NOTAFTER); } YY_BREAK -case 49: +case 51: YY_RULE_SETUP -#line 539 "toke.l" +#line 544 "toke.l" { #ifdef HAVE_SELINUX LEXTRACE("ROLE "); @@ -3132,9 +3124,9 @@ YY_RULE_SETUP #endif } YY_BREAK -case 50: +case 52: YY_RULE_SETUP -#line 548 "toke.l" +#line 553 "toke.l" { #ifdef HAVE_SELINUX LEXTRACE("TYPE "); @@ -3144,9 +3136,9 @@ YY_RULE_SETUP #endif } YY_BREAK -case 51: +case 53: YY_RULE_SETUP -#line 556 "toke.l" +#line 561 "toke.l" { #ifdef HAVE_PRIV_SET LEXTRACE("PRIVS "); @@ -3156,9 +3148,9 @@ YY_RULE_SETUP #endif } YY_BREAK -case 52: +case 54: YY_RULE_SETUP -#line 565 "toke.l" +#line 570 "toke.l" { #ifdef HAVE_PRIV_SET LEXTRACE("LIMITPRIVS "); @@ -3168,9 +3160,9 @@ YY_RULE_SETUP #endif } YY_BREAK -case 53: +case 55: YY_RULE_SETUP -#line 574 "toke.l" +#line 579 "toke.l" { got_alias: if (!fill(sudoerstext, sudoersleng)) @@ -3179,9 +3171,9 @@ YY_RULE_SETUP LEXRETURN(ALIAS); } YY_BREAK -case 54: +case 56: YY_RULE_SETUP -#line 582 "toke.l" +#line 587 "toke.l" { /* XXX - no way to specify digest for command */ /* no command args allowed for Defaults!/path */ @@ -3191,9 +3183,9 @@ YY_RULE_SETUP LEXRETURN(COMMAND); } YY_BREAK -case 55: +case 57: YY_RULE_SETUP -#line 591 "toke.l" +#line 596 "toke.l" { digest_type = SUDO_DIGEST_SHA224; BEGIN WANTDIGEST; @@ -3201,9 +3193,9 @@ YY_RULE_SETUP LEXRETURN(SHA224_TOK); } YY_BREAK -case 56: +case 58: YY_RULE_SETUP -#line 598 "toke.l" +#line 603 "toke.l" { digest_type = SUDO_DIGEST_SHA256; BEGIN WANTDIGEST; @@ -3211,9 +3203,9 @@ YY_RULE_SETUP LEXRETURN(SHA256_TOK); } YY_BREAK -case 57: +case 59: YY_RULE_SETUP -#line 605 "toke.l" +#line 610 "toke.l" { digest_type = SUDO_DIGEST_SHA384; BEGIN WANTDIGEST; @@ -3221,9 +3213,9 @@ YY_RULE_SETUP LEXRETURN(SHA384_TOK); } YY_BREAK -case 58: +case 60: YY_RULE_SETUP -#line 612 "toke.l" +#line 617 "toke.l" { digest_type = SUDO_DIGEST_SHA512; BEGIN WANTDIGEST; @@ -3231,9 +3223,9 @@ YY_RULE_SETUP LEXRETURN(SHA512_TOK); } YY_BREAK -case 59: +case 61: YY_RULE_SETUP -#line 619 "toke.l" +#line 624 "toke.l" { BEGIN GOTCMND; LEXTRACE("COMMAND "); @@ -3241,9 +3233,9 @@ YY_RULE_SETUP yyterminate(); } /* sudo -e */ YY_BREAK -case 60: +case 62: YY_RULE_SETUP -#line 626 "toke.l" +#line 631 "toke.l" { /* directories can't have args... */ if (sudoerstext[sudoersleng - 1] == '/') { @@ -3259,9 +3251,9 @@ YY_RULE_SETUP } } /* a pathname */ YY_BREAK -case 61: +case 63: YY_RULE_SETUP -#line 641 "toke.l" +#line 646 "toke.l" { LEXTRACE("BEGINSTR "); sudoerslval.string = NULL; @@ -3269,9 +3261,9 @@ YY_RULE_SETUP BEGIN INSTR; } YY_BREAK -case 62: +case 64: YY_RULE_SETUP -#line 648 "toke.l" +#line 653 "toke.l" { /* a word */ if (!fill(sudoerstext, sudoersleng)) @@ -3280,49 +3272,73 @@ YY_RULE_SETUP LEXRETURN(WORD); } YY_BREAK -case 63: -YY_RULE_SETUP -#line 656 "toke.l" -{ - LEXTRACE("( "); - LEXRETURN('('); - } - YY_BREAK -case 64: -YY_RULE_SETUP -#line 661 "toke.l" -{ - LEXTRACE(") "); - LEXRETURN(')'); - } - YY_BREAK + case 65: YY_RULE_SETUP -#line 666 "toke.l" +#line 662 "toke.l" { - LEXTRACE(", "); - LEXRETURN(','); - } /* return ',' */ + /* include file/directory */ + if (!fill(sudoerstext, sudoersleng)) + yyterminate(); + BEGIN INITIAL; + LEXTRACE("WORD(6) "); + LEXRETURN(WORD); + } YY_BREAK case 66: YY_RULE_SETUP #line 671 "toke.l" +{ + LEXTRACE("BEGINSTR "); + sudoerslval.string = NULL; + prev_state = INITIAL; + BEGIN INSTR; + } + YY_BREAK + +case 67: +YY_RULE_SETUP +#line 679 "toke.l" +{ + LEXTRACE("( "); + LEXRETURN('('); + } + YY_BREAK +case 68: +YY_RULE_SETUP +#line 684 "toke.l" +{ + LEXTRACE(") "); + LEXRETURN(')'); + } + YY_BREAK +case 69: +YY_RULE_SETUP +#line 689 "toke.l" +{ + LEXTRACE(", "); + LEXRETURN(','); + } /* return ',' */ + YY_BREAK +case 70: +YY_RULE_SETUP +#line 694 "toke.l" { LEXTRACE("= "); LEXRETURN('='); } /* return '=' */ YY_BREAK -case 67: +case 71: YY_RULE_SETUP -#line 676 "toke.l" +#line 699 "toke.l" { LEXTRACE(": "); LEXRETURN(':'); } /* return ':' */ YY_BREAK -case 68: +case 72: YY_RULE_SETUP -#line 681 "toke.l" +#line 704 "toke.l" { if (sudoersleng & 1) { LEXTRACE("!"); @@ -3330,10 +3346,10 @@ YY_RULE_SETUP } } YY_BREAK -case 69: -/* rule 69 can match eol */ +case 73: +/* rule 73 can match eol */ YY_RULE_SETUP -#line 688 "toke.l" +#line 711 "toke.l" { if (YY_START == INSTR) { LEXTRACE("ERROR "); @@ -3346,27 +3362,27 @@ YY_RULE_SETUP LEXRETURN(COMMENT); } /* return newline */ YY_BREAK -case 70: +case 74: YY_RULE_SETUP -#line 700 "toke.l" +#line 723 "toke.l" { /* throw away space/tabs */ sawspace = true; /* but remember for fill_args */ } YY_BREAK -case 71: -/* rule 71 can match eol */ +case 75: +/* rule 75 can match eol */ YY_RULE_SETUP -#line 704 "toke.l" +#line 727 "toke.l" { sawspace = true; /* remember for fill_args */ sudolineno++; continued = true; } /* throw away EOL after \ */ YY_BREAK -case 72: -/* rule 72 can match eol */ +case 76: +/* rule 76 can match eol */ YY_RULE_SETUP -#line 710 "toke.l" +#line 733 "toke.l" { if (sudoerstext[sudoersleng - 1] == '\n') { /* comment ending in a newline */ @@ -3381,9 +3397,9 @@ YY_RULE_SETUP LEXRETURN(COMMENT); } /* comment, not uid/gid */ YY_BREAK -case 73: +case 77: YY_RULE_SETUP -#line 724 "toke.l" +#line 747 "toke.l" { LEXTRACE("ERROR "); LEXRETURN(ERROR); @@ -3396,7 +3412,8 @@ case YY_STATE_EOF(STARTDEFS): case YY_STATE_EOF(INDEFS): case YY_STATE_EOF(INSTR): case YY_STATE_EOF(WANTDIGEST): -#line 729 "toke.l" +case YY_STATE_EOF(GOTINC): +#line 752 "toke.l" { if (YY_START != INITIAL) { BEGIN INITIAL; @@ -3407,12 +3424,12 @@ case YY_STATE_EOF(WANTDIGEST): yyterminate(); } YY_BREAK -case 74: +case 78: YY_RULE_SETUP -#line 739 "toke.l" +#line 762 "toke.l" ECHO; YY_BREAK -#line 3410 "toke.c" +#line 3427 "toke.c" case YY_END_OF_BUFFER: { @@ -3706,7 +3723,7 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 896 ) + if ( yy_current_state >= 916 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -3734,11 +3751,11 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 896 ) + if ( yy_current_state >= 916 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 895); + yy_is_jam = (yy_current_state == 915); return yy_is_jam ? 0 : yy_current_state; } @@ -4373,7 +4390,7 @@ void sudoersfree (void * ptr ) #define YYTABLES_NAME "yytables" -#line 739 "toke.l" +#line 762 "toke.l" struct path_list { @@ -4553,18 +4570,91 @@ init_lexer(void) debug_return; } +/* + * Expand any embedded %h (host) escapes in the given path and makes + * a relative path fully-qualified based on the current sudoers file. + * Returns a reference-counted string. + */ +static char * +expand_include(const char *opath, size_t olen) +{ + const char *cp, *ep; + char *path, *pp; + int dirlen = 0, len; + size_t shost_len = 0; + bool subst = false; + debug_decl(expand_include, SUDOERS_DEBUG_PARSER); + + /* Strip double quotes if present. */ + if (*opath == '"') { + opath++; + olen -= 2; + } + + /* Relative paths are located in the same dir as the sudoers file. */ + if (*opath != '/') { + char *dirend = strrchr(sudoers, '/'); + if (dirend != NULL) + dirlen = (int)(dirend - sudoers) + 1; + } + + len = olen; + for (cp = opath, ep = opath + olen; cp < ep; cp++) { + if (cp[0] == '%' && cp[1] == 'h') { + shost_len = strlen(user_shost); + len += shost_len - 2; + subst = true; + } + } + + /* Make a copy of the fully-qualified path and return it. */ + path = pp = rcstr_alloc(len + dirlen); + if (path == NULL) { + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + sudoerserror(NULL); + debug_return_str(NULL); + } + if (dirlen) { + memcpy(path, sudoers, dirlen); + pp += dirlen; + } + if (subst) { + /* substitute for %h */ + cp = opath; + while (cp < ep) { + if (cp[0] == '%' && cp[1] == 'h') { + memcpy(pp, user_shost, shost_len); + pp += shost_len; + cp += 2; + continue; + } + *pp++ = *cp++; + } + *pp = '\0'; + } else { + memcpy(pp, opath, len); + pp[len] = '\0'; + } + + debug_return_str(path); +} + /* * Open an include file (or file from a directory), push the old * sudoers file buffer and switch to the new one. * A missing or insecure include dir is simply ignored. * Returns false on error, else true. */ -static bool -push_include_int(char *path, bool isdir) +bool +push_include(const char *opath, bool isdir) { struct path_list *pl; + char *path; FILE *fp; - debug_decl(push_include_int, SUDOERS_DEBUG_PARSER); + debug_decl(push_include, SUDOERS_DEBUG_PARSER); + + if ((path = expand_include(opath, strlen(opath))) == NULL) + debug_return_bool(false); /* push current state onto stack */ if (idepth >= istacksize) { @@ -4704,72 +4794,6 @@ pop_include(void) debug_return_bool(true); } -static char * -parse_include_int(const char *base, bool isdir) -{ - const char *cp, *ep; - char *path, *pp; - int dirlen = 0, len = 0, subst = 0; - size_t shost_len = 0; - debug_decl(parse_include, SUDOERS_DEBUG_PARSER); - - /* Pull out path from #include line. */ - cp = base + (isdir ? sizeof("#includedir") : sizeof("#include")); - while (isblank((unsigned char) *cp)) - cp++; - ep = cp; - while (*ep != '\0' && !isspace((unsigned char) *ep)) { - if (ep[0] == '%' && ep[1] == 'h') { - shost_len = strlen(user_shost); - len += shost_len - 2; - subst = 1; - } - ep++; - } - - /* Relative paths are located in the same dir as the sudoers file. */ - if (*cp != '/') { - char *dirend = strrchr(sudoers, '/'); - if (dirend != NULL) - dirlen = (int)(dirend - sudoers) + 1; - } - - /* Make a copy of the fully-qualified path and return it. */ - len += (int)(ep - cp); - path = pp = rcstr_alloc(len + dirlen); - if (path == NULL) { - sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - sudoerserror(NULL); - debug_return_str(NULL); - } - if (dirlen) { - memcpy(path, sudoers, dirlen); - pp += dirlen; - } - if (subst) { - /* substitute for %h */ - while (cp < ep) { - if (cp[0] == '%' && cp[1] == 'h') { - memcpy(pp, user_shost, shost_len); - pp += shost_len; - cp += 2; - continue; - } - *pp++ = *cp++; - } - *pp = '\0'; - } else { - memcpy(pp, cp, len); - pp[len] = '\0'; - } - - /* Push any excess characters (e.g. comment, newline) back to the lexer */ - if (*ep != '\0') - yyless((int)(ep - base)); - - debug_return_str(path); -} - #ifdef TRACELEXER int sudoers_trace_print(const char *msg) diff --git a/plugins/sudoers/toke.h b/plugins/sudoers/toke.h index 575697904..6450fb783 100644 --- a/plugins/sudoers/toke.h +++ b/plugins/sudoers/toke.h @@ -24,8 +24,9 @@ bool fill_args(const char *, size_t, int); bool fill_cmnd(const char *, size_t); bool fill_txt(const char *, size_t, size_t); bool ipv6_valid(const char *s); -int sudoers_trace_print(const char *msg); +int sudoers_trace_print(const char *); void sudoerserror(const char *); +bool push_include(const char *, bool); #ifndef FLEX_SCANNER extern int (*trace_print)(const char *msg); diff --git a/plugins/sudoers/toke.l b/plugins/sudoers/toke.l index d23019bf7..1cd9a4aa5 100644 --- a/plugins/sudoers/toke.l +++ b/plugins/sudoers/toke.l @@ -64,9 +64,7 @@ static bool continued, sawspace; static int prev_state; static int digest_type = -1; -static bool push_include_int(char *, bool); static bool pop_include(void); -static char *parse_include_int(const char *, bool); int (*trace_print)(const char *msg) = sudoers_trace_print; @@ -76,11 +74,6 @@ int (*trace_print)(const char *msg) = sudoers_trace_print; } while (0) #define ECHO ignore_result(fwrite(sudoerstext, sudoersleng, 1, sudoersout)) - -#define parse_include(_p) (parse_include_int((_p), false)) -#define parse_includedir(_p) (parse_include_int((_p), true)) -#define push_include(_p) (push_include_int((_p), false)) -#define push_includedir(_p) (push_include_int((_p), true)) %} HEX16 [0-9A-Fa-f]{1,4} @@ -106,6 +99,7 @@ DEFVAR [a-z_]+ %x INDEFS %x INSTR %s WANTDIGEST +%x GOTINC %% [[:blank:]]*,[[:blank:]]* { @@ -280,43 +274,54 @@ DEFVAR [a-z_]+ yyless(sudoersleng); } /* base64 digest */ -^#include[[:blank:]]+.*(\r\n|\n)? { - char *path; - +@include { if (continued) { LEXTRACE("ERROR "); LEXRETURN(ERROR); } - if ((path = parse_include(sudoerstext)) == NULL) - yyterminate(); + BEGIN GOTINC; + LEXTRACE("INCLUDE "); + LEXRETURN(INCLUDE); + } - LEXTRACE("INCLUDE\n"); +@includedir { + if (continued) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } - /* Push current buffer and switch to include file */ - if (!push_include(path)) - yyterminate(); + BEGIN GOTINC; + LEXTRACE("INCLUDEDIR "); + LEXRETURN(INCLUDEDIR); + } + +^#include[[:blank:]]+.*(\r\n|\n)? { + if (continued) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + + /* only consume #include */ + yyless(sizeof("#include") - 1); + + BEGIN GOTINC; + LEXTRACE("INCLUDE "); + LEXRETURN(INCLUDE); } ^#includedir[[:blank:]]+.*(\r\n|\n)? { - char *path; - if (continued) { LEXTRACE("ERROR "); LEXRETURN(ERROR); } - if ((path = parse_includedir(sudoerstext)) == NULL) - yyterminate(); + /* only consume #includedir */ + yyless(sizeof("#includedir") - 1); - LEXTRACE("INCLUDEDIR\n"); - - /* - * Push current buffer and switch to include file, - * ignoring missing or empty directories. - */ - if (!push_includedir(path)) - yyterminate(); + BEGIN GOTINC; + LEXTRACE("INCLUDEDIR "); + LEXRETURN(INCLUDEDIR); } ^[[:blank:]]*Defaults([:@>\!][[:blank:]]*\!*\"?({ID}|{WORD}))? { @@ -638,7 +643,7 @@ sudoedit { } } /* a pathname */ -\" { +\" { LEXTRACE("BEGINSTR "); sudoerslval.string = NULL; prev_state = YY_START; @@ -653,6 +658,24 @@ sudoedit { LEXRETURN(WORD); } +{ + [^\"[:space:]]([^[:space:]]|\\[[:blank:]])* { + /* include file/directory */ + if (!fill(sudoerstext, sudoersleng)) + yyterminate(); + BEGIN INITIAL; + LEXTRACE("WORD(6) "); + LEXRETURN(WORD); + } + + \" { + LEXTRACE("BEGINSTR "); + sudoerslval.string = NULL; + prev_state = INITIAL; + BEGIN INSTR; + } +} + \( { LEXTRACE("( "); LEXRETURN('('); @@ -914,18 +937,91 @@ init_lexer(void) debug_return; } +/* + * Expand any embedded %h (host) escapes in the given path and makes + * a relative path fully-qualified based on the current sudoers file. + * Returns a reference-counted string. + */ +static char * +expand_include(const char *opath, size_t olen) +{ + const char *cp, *ep; + char *path, *pp; + int dirlen = 0, len; + size_t shost_len = 0; + bool subst = false; + debug_decl(expand_include, SUDOERS_DEBUG_PARSER); + + /* Strip double quotes if present. */ + if (*opath == '"') { + opath++; + olen -= 2; + } + + /* Relative paths are located in the same dir as the sudoers file. */ + if (*opath != '/') { + char *dirend = strrchr(sudoers, '/'); + if (dirend != NULL) + dirlen = (int)(dirend - sudoers) + 1; + } + + len = olen; + for (cp = opath, ep = opath + olen; cp < ep; cp++) { + if (cp[0] == '%' && cp[1] == 'h') { + shost_len = strlen(user_shost); + len += shost_len - 2; + subst = true; + } + } + + /* Make a copy of the fully-qualified path and return it. */ + path = pp = rcstr_alloc(len + dirlen); + if (path == NULL) { + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + sudoerserror(NULL); + debug_return_str(NULL); + } + if (dirlen) { + memcpy(path, sudoers, dirlen); + pp += dirlen; + } + if (subst) { + /* substitute for %h */ + cp = opath; + while (cp < ep) { + if (cp[0] == '%' && cp[1] == 'h') { + memcpy(pp, user_shost, shost_len); + pp += shost_len; + cp += 2; + continue; + } + *pp++ = *cp++; + } + *pp = '\0'; + } else { + memcpy(pp, opath, len); + pp[len] = '\0'; + } + + debug_return_str(path); +} + /* * Open an include file (or file from a directory), push the old * sudoers file buffer and switch to the new one. * A missing or insecure include dir is simply ignored. * Returns false on error, else true. */ -static bool -push_include_int(char *path, bool isdir) +bool +push_include(const char *opath, bool isdir) { struct path_list *pl; + char *path; FILE *fp; - debug_decl(push_include_int, SUDOERS_DEBUG_PARSER); + debug_decl(push_include, SUDOERS_DEBUG_PARSER); + + if ((path = expand_include(opath, strlen(opath))) == NULL) + debug_return_bool(false); /* push current state onto stack */ if (idepth >= istacksize) { @@ -1065,72 +1161,6 @@ pop_include(void) debug_return_bool(true); } -static char * -parse_include_int(const char *base, bool isdir) -{ - const char *cp, *ep; - char *path, *pp; - int dirlen = 0, len = 0, subst = 0; - size_t shost_len = 0; - debug_decl(parse_include, SUDOERS_DEBUG_PARSER); - - /* Pull out path from #include line. */ - cp = base + (isdir ? sizeof("#includedir") : sizeof("#include")); - while (isblank((unsigned char) *cp)) - cp++; - ep = cp; - while (*ep != '\0' && !isspace((unsigned char) *ep)) { - if (ep[0] == '%' && ep[1] == 'h') { - shost_len = strlen(user_shost); - len += shost_len - 2; - subst = 1; - } - ep++; - } - - /* Relative paths are located in the same dir as the sudoers file. */ - if (*cp != '/') { - char *dirend = strrchr(sudoers, '/'); - if (dirend != NULL) - dirlen = (int)(dirend - sudoers) + 1; - } - - /* Make a copy of the fully-qualified path and return it. */ - len += (int)(ep - cp); - path = pp = rcstr_alloc(len + dirlen); - if (path == NULL) { - sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - sudoerserror(NULL); - debug_return_str(NULL); - } - if (dirlen) { - memcpy(path, sudoers, dirlen); - pp += dirlen; - } - if (subst) { - /* substitute for %h */ - while (cp < ep) { - if (cp[0] == '%' && cp[1] == 'h') { - memcpy(pp, user_shost, shost_len); - pp += shost_len; - cp += 2; - continue; - } - *pp++ = *cp++; - } - *pp = '\0'; - } else { - memcpy(pp, cp, len); - pp[len] = '\0'; - } - - /* Push any excess characters (e.g. comment, newline) back to the lexer */ - if (*ep != '\0') - yyless((int)(ep - base)); - - debug_return_str(path); -} - #ifdef TRACELEXER int sudoers_trace_print(const char *msg)