diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in index 4adf58d77..9d766a920 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@" "October 20, 2019" "Sudo @PACKAGE_VERSION@" "File Formats Manual" +.TH "SUDOERS" "@mansectform@" "November 5, 2019" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .nh .if n .ad l .SH "NAME" @@ -947,7 +947,17 @@ is a command built into \fBsudo\fR itself and must be specified in the \fIsudoers\fR -file without a leading path. +file +\fBwithout\fR +a leading path. +If a leading path is present, for example +\fI/usr/bin/sudoedit\fR, +the path name will be silently converted to +\(lq\fRsudoedit\fR\(rq. +A fully-qualified path for +\fBsudoedit\fR +is treated as an error by +\fBvisudo\fR. .PP If a \fRcommand name\fR diff --git a/doc/sudoers.mdoc.in b/doc/sudoers.mdoc.in index b11c0b906..26a740d55 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 October 20, 2019 +.Dd November 5, 2019 .Dt SUDOERS @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -911,7 +911,17 @@ is a command built into .Nm sudo itself and must be specified in the .Em sudoers -file without a leading path. +file +.Sy without +a leading path. +If a leading path is present, for example +.Pa /usr/bin/sudoedit , +the path name will be silently converted to +.Dq Li sudoedit . +A fully-qualified path for +.Nm sudoedit +is treated as an error by +.Nm visudo . .Pp If a .Li command name diff --git a/plugins/sudoers/cvtsudoers.c b/plugins/sudoers/cvtsudoers.c index fe4fc3805..9dad67707 100644 --- a/plugins/sudoers/cvtsudoers.c +++ b/plugins/sudoers/cvtsudoers.c @@ -637,7 +637,7 @@ parse_sudoers(const char *input_file, struct cvtsudoers_config *conf) input_file = "stdin"; } else if ((sudoersin = fopen(input_file, "r")) == NULL) sudo_fatal(U_("unable to open %s"), input_file); - init_parser(input_file, false); + init_parser(input_file, false, true); if (sudoersparse() && !parse_error) { sudo_warnx(U_("failed to parse %s file, unknown error"), input_file); parse_error = true; diff --git a/plugins/sudoers/gram.c b/plugins/sudoers/gram.c index 103f11285..f7c1155bc 100644 --- a/plugins/sudoers/gram.c +++ b/plugins/sudoers/gram.c @@ -99,6 +99,7 @@ * Globals */ bool sudoers_warnings = true; +bool sudoers_strict = false; bool parse_error = false; int errorlineno = -1; char *errorfile = NULL; @@ -120,7 +121,7 @@ static bool add_userspec(struct member *, struct privilege *); static struct defaults *new_default(char *, char *, short); static struct member *new_member(char *, int); static struct command_digest *new_digest(int, char *); -#line 82 "gram.y" +#line 83 "gram.y" #ifndef YYSTYPE_DEFINED #define YYSTYPE_DEFINED typedef union { @@ -137,7 +138,7 @@ typedef union { int tok; } YYSTYPE; #endif /* YYSTYPE_DEFINED */ -#line 135 "gram.c" +#line 136 "gram.c" #define COMMAND 257 #define ALIAS 258 #define DEFVAR 259 @@ -677,7 +678,7 @@ short *yysslim; YYSTYPE *yyvs; unsigned int yystacksize; int yyparse(void); -#line 910 "gram.y" +#line 911 "gram.y" void sudoerserror(const char *s) { @@ -1060,7 +1061,7 @@ free_parse_tree(struct sudoers_parse_tree *parse_tree) * the current sudoers file to path. */ bool -init_parser(const char *path, bool quiet) +init_parser(const char *path, bool quiet, bool strict) { bool ret = true; debug_decl(init_parser, SUDOERS_DEBUG_PARSER) @@ -1083,6 +1084,7 @@ init_parser(const char *path, bool quiet) rcstr_delref(errorfile); errorfile = NULL; sudoers_warnings = !quiet; + sudoers_strict = strict; debug_return_bool(ret); } @@ -1105,7 +1107,7 @@ init_options(struct command_options *opts) opts->limitprivs = NULL; #endif } -#line 1051 "gram.c" +#line 1053 "gram.c" /* allocate initial stack or double stack size, up to YYMAXDEPTH */ #if defined(__cplusplus) || defined(__STDC__) static int yygrowstack(void) @@ -1314,23 +1316,23 @@ yyreduce: switch (yyn) { case 1: -#line 180 "gram.y" +#line 181 "gram.y" { ; } break; case 5: -#line 188 "gram.y" +#line 189 "gram.y" { ; } break; case 6: -#line 191 "gram.y" +#line 192 "gram.y" { yyerrok; } break; case 7: -#line 194 "gram.y" +#line 195 "gram.y" { if (!add_userspec(yyvsp[-1].member, yyvsp[0].privilege)) { sudoerserror(N_("unable to allocate memory")); @@ -1339,73 +1341,73 @@ case 7: } break; case 8: -#line 200 "gram.y" +#line 201 "gram.y" { ; } break; case 9: -#line 203 "gram.y" +#line 204 "gram.y" { ; } break; case 10: -#line 206 "gram.y" +#line 207 "gram.y" { ; } break; case 11: -#line 209 "gram.y" +#line 210 "gram.y" { ; } break; case 12: -#line 212 "gram.y" +#line 213 "gram.y" { if (!add_defaults(DEFAULTS, NULL, yyvsp[0].defaults)) YYERROR; } break; case 13: -#line 216 "gram.y" +#line 217 "gram.y" { if (!add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; case 14: -#line 220 "gram.y" +#line 221 "gram.y" { if (!add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; case 15: -#line 224 "gram.y" +#line 225 "gram.y" { if (!add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; case 16: -#line 228 "gram.y" +#line 229 "gram.y" { if (!add_defaults(DEFAULTS_CMND, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; case 18: -#line 235 "gram.y" +#line 236 "gram.y" { HLTQ_CONCAT(yyvsp[-2].defaults, yyvsp[0].defaults, entries); yyval.defaults = yyvsp[-2].defaults; } break; case 19: -#line 241 "gram.y" +#line 242 "gram.y" { yyval.defaults = new_default(yyvsp[0].string, NULL, true); if (yyval.defaults == NULL) { @@ -1415,7 +1417,7 @@ case 19: } break; case 20: -#line 248 "gram.y" +#line 249 "gram.y" { yyval.defaults = new_default(yyvsp[0].string, NULL, false); if (yyval.defaults == NULL) { @@ -1425,7 +1427,7 @@ case 20: } break; case 21: -#line 255 "gram.y" +#line 256 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, true); if (yyval.defaults == NULL) { @@ -1435,7 +1437,7 @@ case 21: } break; case 22: -#line 262 "gram.y" +#line 263 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '+'); if (yyval.defaults == NULL) { @@ -1445,7 +1447,7 @@ case 22: } break; case 23: -#line 269 "gram.y" +#line 270 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '-'); if (yyval.defaults == NULL) { @@ -1455,14 +1457,14 @@ case 23: } break; case 25: -#line 279 "gram.y" +#line 280 "gram.y" { HLTQ_CONCAT(yyvsp[-2].privilege, yyvsp[0].privilege, entries); yyval.privilege = yyvsp[-2].privilege; } break; case 26: -#line 285 "gram.y" +#line 286 "gram.y" { struct privilege *p = calloc(1, sizeof(*p)); if (p == NULL) { @@ -1477,21 +1479,21 @@ case 26: } break; case 27: -#line 299 "gram.y" +#line 300 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; case 28: -#line 303 "gram.y" +#line 304 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; case 29: -#line 309 "gram.y" +#line 310 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -1501,7 +1503,7 @@ case 29: } break; case 30: -#line 316 "gram.y" +#line 317 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -1511,7 +1513,7 @@ case 30: } break; case 31: -#line 323 "gram.y" +#line 324 "gram.y" { yyval.member = new_member(yyvsp[0].string, NETGROUP); if (yyval.member == NULL) { @@ -1521,7 +1523,7 @@ case 31: } break; case 32: -#line 330 "gram.y" +#line 331 "gram.y" { yyval.member = new_member(yyvsp[0].string, NTWKADDR); if (yyval.member == NULL) { @@ -1531,7 +1533,7 @@ case 32: } break; case 33: -#line 337 "gram.y" +#line 338 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); if (yyval.member == NULL) { @@ -1541,7 +1543,7 @@ case 33: } break; case 35: -#line 347 "gram.y" +#line 348 "gram.y" { struct cmndspec *prev; prev = HLTQ_LAST(yyvsp[-2].cmndspec, cmndspec, entries); @@ -1595,7 +1597,7 @@ case 35: } break; case 36: -#line 400 "gram.y" +#line 401 "gram.y" { struct cmndspec *cs = calloc(1, sizeof(*cs)); if (cs == NULL) { @@ -1649,7 +1651,7 @@ case 36: } break; case 37: -#line 453 "gram.y" +#line 454 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA224, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1659,7 +1661,7 @@ case 37: } break; case 38: -#line 460 "gram.y" +#line 461 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA256, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1669,7 +1671,7 @@ case 38: } break; case 39: -#line 467 "gram.y" +#line 468 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA384, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1679,7 +1681,7 @@ case 39: } break; case 40: -#line 474 "gram.y" +#line 475 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA512, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1689,13 +1691,13 @@ case 40: } break; case 41: -#line 483 "gram.y" +#line 484 "gram.y" { yyval.member = yyvsp[0].member; } break; case 42: -#line 486 "gram.y" +#line 487 "gram.y" { if (yyvsp[0].member->type != COMMAND) { sudoerserror(N_("a digest requires a path name")); @@ -1707,75 +1709,75 @@ case 42: } break; case 43: -#line 497 "gram.y" +#line 498 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; case 44: -#line 501 "gram.y" +#line 502 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; case 45: -#line 507 "gram.y" +#line 508 "gram.y" { yyval.string = yyvsp[0].string; } break; case 46: -#line 512 "gram.y" +#line 513 "gram.y" { yyval.string = yyvsp[0].string; } break; case 47: -#line 516 "gram.y" +#line 517 "gram.y" { yyval.string = yyvsp[0].string; } break; case 48: -#line 521 "gram.y" +#line 522 "gram.y" { yyval.string = yyvsp[0].string; } break; case 49: -#line 526 "gram.y" +#line 527 "gram.y" { yyval.string = yyvsp[0].string; } break; case 50: -#line 531 "gram.y" +#line 532 "gram.y" { yyval.string = yyvsp[0].string; } break; case 51: -#line 535 "gram.y" +#line 536 "gram.y" { yyval.string = yyvsp[0].string; } break; case 52: -#line 540 "gram.y" +#line 541 "gram.y" { yyval.runas = NULL; } break; case 53: -#line 543 "gram.y" +#line 544 "gram.y" { yyval.runas = yyvsp[-1].runas; } break; case 54: -#line 548 "gram.y" +#line 549 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas != NULL) { @@ -1793,7 +1795,7 @@ case 54: } break; case 55: -#line 563 "gram.y" +#line 564 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas == NULL) { @@ -1805,7 +1807,7 @@ case 55: } break; case 56: -#line 572 "gram.y" +#line 573 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas == NULL) { @@ -1817,7 +1819,7 @@ case 56: } break; case 57: -#line 581 "gram.y" +#line 582 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas == NULL) { @@ -1829,7 +1831,7 @@ case 57: } break; case 58: -#line 590 "gram.y" +#line 591 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas != NULL) { @@ -1847,13 +1849,13 @@ case 58: } break; case 59: -#line 607 "gram.y" +#line 608 "gram.y" { init_options(&yyval.options); } break; case 60: -#line 610 "gram.y" +#line 611 "gram.y" { yyval.options.notbefore = parse_gentime(yyvsp[0].string); free(yyvsp[0].string); @@ -1864,7 +1866,7 @@ case 60: } break; case 61: -#line 618 "gram.y" +#line 619 "gram.y" { yyval.options.notafter = parse_gentime(yyvsp[0].string); free(yyvsp[0].string); @@ -1875,7 +1877,7 @@ case 61: } break; case 62: -#line 626 "gram.y" +#line 627 "gram.y" { yyval.options.timeout = parse_timeout(yyvsp[0].string); free(yyvsp[0].string); @@ -1889,7 +1891,7 @@ case 62: } break; case 63: -#line 637 "gram.y" +#line 638 "gram.y" { #ifdef HAVE_SELINUX free(yyval.options.role); @@ -1898,7 +1900,7 @@ case 63: } break; case 64: -#line 643 "gram.y" +#line 644 "gram.y" { #ifdef HAVE_SELINUX free(yyval.options.type); @@ -1907,7 +1909,7 @@ case 64: } break; case 65: -#line 649 "gram.y" +#line 650 "gram.y" { #ifdef HAVE_PRIV_SET free(yyval.options.privs); @@ -1916,7 +1918,7 @@ case 65: } break; case 66: -#line 655 "gram.y" +#line 656 "gram.y" { #ifdef HAVE_PRIV_SET free(yyval.options.limitprivs); @@ -1925,97 +1927,97 @@ case 66: } break; case 67: -#line 663 "gram.y" +#line 664 "gram.y" { TAGS_INIT(yyval.tag); } break; case 68: -#line 666 "gram.y" +#line 667 "gram.y" { yyval.tag.nopasswd = true; } break; case 69: -#line 669 "gram.y" +#line 670 "gram.y" { yyval.tag.nopasswd = false; } break; case 70: -#line 672 "gram.y" +#line 673 "gram.y" { yyval.tag.noexec = true; } break; case 71: -#line 675 "gram.y" +#line 676 "gram.y" { yyval.tag.noexec = false; } break; case 72: -#line 678 "gram.y" +#line 679 "gram.y" { yyval.tag.setenv = true; } break; case 73: -#line 681 "gram.y" +#line 682 "gram.y" { yyval.tag.setenv = false; } break; case 74: -#line 684 "gram.y" +#line 685 "gram.y" { yyval.tag.log_input = true; } break; case 75: -#line 687 "gram.y" +#line 688 "gram.y" { yyval.tag.log_input = false; } break; case 76: -#line 690 "gram.y" +#line 691 "gram.y" { yyval.tag.log_output = true; } break; case 77: -#line 693 "gram.y" +#line 694 "gram.y" { yyval.tag.log_output = false; } break; case 78: -#line 696 "gram.y" +#line 697 "gram.y" { yyval.tag.follow = true; } break; case 79: -#line 699 "gram.y" +#line 700 "gram.y" { yyval.tag.follow = false; } break; case 80: -#line 702 "gram.y" +#line 703 "gram.y" { yyval.tag.send_mail = true; } break; case 81: -#line 705 "gram.y" +#line 706 "gram.y" { yyval.tag.send_mail = false; } break; case 82: -#line 710 "gram.y" +#line 711 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -2025,7 +2027,7 @@ case 82: } break; case 83: -#line 717 "gram.y" +#line 718 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -2035,7 +2037,7 @@ case 83: } break; case 84: -#line 724 "gram.y" +#line 725 "gram.y" { struct sudo_command *c = calloc(1, sizeof(*c)); if (c == NULL) { @@ -2053,7 +2055,7 @@ case 84: } break; case 87: -#line 745 "gram.y" +#line 746 "gram.y" { const char *s; s = alias_add(&parsed_policy, yyvsp[-2].string, HOSTALIAS, @@ -2065,14 +2067,14 @@ case 87: } break; case 89: -#line 757 "gram.y" +#line 758 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; case 92: -#line 767 "gram.y" +#line 768 "gram.y" { const char *s; s = alias_add(&parsed_policy, yyvsp[-2].string, CMNDALIAS, @@ -2084,14 +2086,14 @@ case 92: } break; case 94: -#line 779 "gram.y" +#line 780 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; case 97: -#line 789 "gram.y" +#line 790 "gram.y" { const char *s; s = alias_add(&parsed_policy, yyvsp[-2].string, RUNASALIAS, @@ -2103,7 +2105,7 @@ case 97: } break; case 100: -#line 804 "gram.y" +#line 805 "gram.y" { const char *s; s = alias_add(&parsed_policy, yyvsp[-2].string, USERALIAS, @@ -2115,28 +2117,28 @@ case 100: } break; case 102: -#line 816 "gram.y" +#line 817 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; case 103: -#line 822 "gram.y" +#line 823 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; case 104: -#line 826 "gram.y" +#line 827 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; case 105: -#line 832 "gram.y" +#line 833 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -2146,7 +2148,7 @@ case 105: } break; case 106: -#line 839 "gram.y" +#line 840 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -2156,7 +2158,7 @@ case 106: } break; case 107: -#line 846 "gram.y" +#line 847 "gram.y" { yyval.member = new_member(yyvsp[0].string, NETGROUP); if (yyval.member == NULL) { @@ -2166,7 +2168,7 @@ case 107: } break; case 108: -#line 853 "gram.y" +#line 854 "gram.y" { yyval.member = new_member(yyvsp[0].string, USERGROUP); if (yyval.member == NULL) { @@ -2176,7 +2178,7 @@ case 108: } break; case 109: -#line 860 "gram.y" +#line 861 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); if (yyval.member == NULL) { @@ -2186,28 +2188,28 @@ case 109: } break; case 111: -#line 870 "gram.y" +#line 871 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; case 112: -#line 876 "gram.y" +#line 877 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; case 113: -#line 880 "gram.y" +#line 881 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; case 114: -#line 886 "gram.y" +#line 887 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -2217,7 +2219,7 @@ case 114: } break; case 115: -#line 893 "gram.y" +#line 894 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -2227,7 +2229,7 @@ case 115: } break; case 116: -#line 900 "gram.y" +#line 901 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); if (yyval.member == NULL) { @@ -2236,7 +2238,7 @@ case 116: } } break; -#line 2182 "gram.c" +#line 2184 "gram.c" } yyssp -= yym; yystate = *yyssp; diff --git a/plugins/sudoers/gram.y b/plugins/sudoers/gram.y index 76a2f9f65..8deda48d5 100644 --- a/plugins/sudoers/gram.y +++ b/plugins/sudoers/gram.y @@ -56,6 +56,7 @@ * Globals */ bool sudoers_warnings = true; +bool sudoers_strict = false; bool parse_error = false; int errorlineno = -1; char *errorfile = NULL; @@ -1289,7 +1290,7 @@ free_parse_tree(struct sudoers_parse_tree *parse_tree) * the current sudoers file to path. */ bool -init_parser(const char *path, bool quiet) +init_parser(const char *path, bool quiet, bool strict) { bool ret = true; debug_decl(init_parser, SUDOERS_DEBUG_PARSER) @@ -1312,6 +1313,7 @@ init_parser(const char *path, bool quiet) rcstr_delref(errorfile); errorfile = NULL; sudoers_warnings = !quiet; + sudoers_strict = strict; debug_return_bool(ret); } diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h index f5961f7fd..919297548 100644 --- a/plugins/sudoers/parse.h +++ b/plugins/sudoers/parse.h @@ -290,7 +290,7 @@ void alias_put(struct alias *a); /* gram.c */ extern struct sudoers_parse_tree parsed_policy; -bool init_parser(const char *path, bool quiet); +bool init_parser(const char *path, bool quiet, bool strict); void free_member(struct member *m); void free_members(struct member_list *members); void free_privilege(struct privilege *priv); diff --git a/plugins/sudoers/regress/parser/check_fill.c b/plugins/sudoers/regress/parser/check_fill.c index e254c1cf9..f065b5557 100644 --- a/plugins/sudoers/regress/parser/check_fill.c +++ b/plugins/sudoers/regress/parser/check_fill.c @@ -52,6 +52,7 @@ __dso_public int main(int argc, char *argv[]); */ YYSTYPE sudoerslval; +bool sudoers_strict; struct fill_test { const char *input; diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index 1e8abd82b..7f5af7ca8 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -199,7 +199,7 @@ sudoers_policy_init(void *info, char * const envp[]) */ sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); sudo_warn_set_locale_func(sudoers_warn_setlocale); - init_parser(sudoers_file, false); + init_parser(sudoers_file, false, false); TAILQ_FOREACH_SAFE(nss, snl, entries, nss_next) { if (nss->open(nss) == -1 || (nss->parse_tree = nss->parse(nss)) == NULL) { TAILQ_REMOVE(snl, nss, entries); @@ -551,7 +551,7 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], } if (def_group_plugin) group_plugin_unload(); - init_parser(NULL, false); + init_parser(NULL, false, false); if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) { /* ret already set appropriately */ @@ -900,6 +900,14 @@ set_cmnd(void) else user_base = user_cmnd; + /* Convert "sudo sudoedit" -> "sudoedit" */ + if (ISSET(sudo_mode, MODE_RUN) && strcmp(user_base, "sudoedit") == 0) { + CLR(sudo_mode, MODE_RUN); + SET(sudo_mode, MODE_EDIT); + sudo_warnx(U_("sudoedit doesn't need to be run via sudo")); + user_base = user_cmnd = "sudoedit"; + } + TAILQ_FOREACH(nss, snl, entries) { if (!update_defaults(nss->parse_tree, NULL, SETDEF_CMND, false)) { log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR, diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index 906dc541a..176effa52 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -286,6 +286,7 @@ extern char *errorfile; extern int errorlineno; extern bool parse_error; extern bool sudoers_warnings; +extern bool sudoers_strict; /* toke.l */ YY_DECL; diff --git a/plugins/sudoers/testsudoers.c b/plugins/sudoers/testsudoers.c index 5ff0760d4..d857da355 100644 --- a/plugins/sudoers/testsudoers.c +++ b/plugins/sudoers/testsudoers.c @@ -281,7 +281,7 @@ main(int argc, char *argv[]) } /* Allocate space for data structures in the parser. */ - init_parser("sudoers", false); + init_parser("sudoers", false, true); /* * Set runas passwd/group entries based on command line or sudoers. diff --git a/plugins/sudoers/toke_util.c b/plugins/sudoers/toke_util.c index c7360385f..a98b375e6 100644 --- a/plugins/sudoers/toke_util.c +++ b/plugins/sudoers/toke_util.c @@ -124,6 +124,22 @@ fill_cmnd(const char *src, size_t len) } *dst = '\0'; + /* Check for sudoedit specified as a fully-qualified path. */ + if ((dst = strrchr(sudoerslval.command.cmnd, '/')) != NULL) { + if (strcmp(dst, "/sudoedit") == 0) { + if (sudoers_strict) { + sudoerserror( + N_("sudoedit should not be specified with a path")); + } + free(sudoerslval.command.cmnd); + if ((sudoerslval.command.cmnd = strdup("sudoedit")) == NULL) { + sudo_warnx(U_("%s: %s"), __func__, + U_("unable to allocate memory")); + debug_return_bool(false); + } + } + } + debug_return_bool(true); } diff --git a/plugins/sudoers/visudo.c b/plugins/sudoers/visudo.c index 80d5f0b6e..308c08d63 100644 --- a/plugins/sudoers/visudo.c +++ b/plugins/sudoers/visudo.c @@ -264,7 +264,7 @@ main(int argc, char *argv[]) */ if ((sudoersin = open_sudoers(sudoers_file, true, NULL)) == NULL) exit(1); - init_parser(sudoers_file, quiet); + init_parser(sudoers_file, quiet, true); sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); (void) sudoersparse(); (void) update_defaults(&parsed_policy, NULL, @@ -608,7 +608,7 @@ reparse_sudoers(char *editor, int editor_argc, char **editor_argv, /* Clean slate for each parse */ if (!init_defaults()) sudo_fatalx(U_("unable to initialize sudoers default values")); - init_parser(sp->path, quiet); + init_parser(sp->path, quiet, true); /* Parse the sudoers temp file(s) */ sudoersrestart(fp); @@ -931,7 +931,7 @@ check_syntax(const char *sudoers_file, bool quiet, bool strict, bool oldperms) } if (!init_defaults()) sudo_fatalx(U_("unable to initialize sudoers default values")); - init_parser(sudoers_file, quiet); + init_parser(sudoers_file, quiet, true); sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); if (sudoersparse() && !parse_error) { if (!quiet)