From: Todd C. Miller Date: Wed, 9 Nov 2016 23:00:12 +0000 (-0700) Subject: Go back to parsing Defaults entries in update_defaults instead of X-Git-Tag: SUDO_1_8_19^2~51 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=79ca752802f4f543a2a08339dafaa53fcd8e7741;p=sudo Go back to parsing Defaults entries in update_defaults instead of as sudoers is read. Otherwise, we cannot properly support early defaults like sudoers_locale. --- diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c index 5bbbb3417..a9a2aa2a6 100644 --- a/plugins/sudoers/defaults.c +++ b/plugins/sudoers/defaults.c @@ -191,6 +191,36 @@ dump_defaults(void) debug_return; } +/* + * Find the index of the specified Defaults name in sudo_defs_table[] + * On success, returns the matching index or -1 on failure. + */ +static int +find_default(const char *name, const char *file, int lineno, bool quiet) +{ + int i; + debug_decl(find_default, SUDOERS_DEBUG_DEFAULTS) + + for (i = 0; sudo_defs_table[i].name != NULL; i++) { + if (strcmp(name, sudo_defs_table[i].name) == 0) + debug_return_int(i); + } + if (!quiet) { + if (lineno > 0) { + sudo_warnx(U_("%s:%d unknown defaults entry \"%s\""), + file, lineno, name); + } else { + sudo_warnx(U_("%s: unknown defaults entry \"%s\""), + file, name); + } + } + debug_return_int(-1); +} + +/* + * Parse a defaults entry, storing the parsed entry in sd_un. + * Returns true on success or false on failure. + */ static bool parse_default_entry(struct sudo_defs_types *def, const char *val, int op, union sudo_defs_val *sd_un, const char *file, int lineno, bool quiet) @@ -301,24 +331,11 @@ parse_default_entry(struct sudo_defs_types *def, const char *val, int op, } struct early_default * -is_early_default(int idx) +is_early_default(const char *name) { struct early_default *early; debug_decl(is_early_default, SUDOERS_DEBUG_DEFAULTS) - for (early = early_defaults; early->idx != -1; early++) { - if (idx == early->idx) - debug_return_ptr(early); - } - debug_return_ptr(NULL); -} - -struct early_default * -is_early_default_byname(const char *name) -{ - struct early_default *early; - debug_decl(is_early_default_byname, SUDOERS_DEBUG_DEFAULTS) - for (early = early_defaults; early->idx != -1; early++) { if (strcmp(name, sudo_defs_table[early->idx].name) == 0) debug_return_ptr(early); @@ -339,23 +356,20 @@ run_callback(struct sudo_defs_types *def) /* * Sets/clears an entry in the defaults structure. * Runs the callback if present on success. - * XXX - deprecated, only used by ldap/sssd */ bool set_default(const char *var, const char *val, int op, const char *file, int lineno, bool quiet) { - union sudo_defs_val sd_un; int idx; debug_decl(set_default, SUDOERS_DEBUG_DEFAULTS) - memset(&sd_un, 0, sizeof(sd_un)); - idx = parse_default(var, val, op, &sd_un, file, lineno, quiet); + idx = find_default(var, file, lineno, quiet); if (idx != -1) { /* Set parsed value in sudo_defs_table and run callback (if any). */ struct sudo_defs_types *def = &sudo_defs_table[idx]; - def->sd_un = sd_un; - debug_return_bool(run_callback(def)); + if (parse_default_entry(def, val, op, &def->sd_un, file, lineno, quiet)) + debug_return_bool(run_callback(def)); } debug_return_bool(false); } @@ -363,25 +377,22 @@ set_default(const char *var, const char *val, int op, const char *file, /* * Like set_default() but stores the matching default value * and does not run callbacks. - * XXX - deprecated, only used by ldap/sssd */ bool set_early_default(const char *var, const char *val, int op, const char *file, int lineno, bool quiet, struct early_default *early) { - union sudo_defs_val sd_un; int idx; debug_decl(set_early_default, SUDOERS_DEBUG_DEFAULTS) - memset(&sd_un, 0, sizeof(sd_un)); - idx = parse_default(var, val, op, &sd_un, file, lineno, quiet); + idx = find_default(var, file, lineno, quiet); if (idx != -1) { - /* Set parsed value in sudo_defs_table. */ + /* Set parsed value in sudo_defs_table but defer callback (if any). */ struct sudo_defs_types *def = &sudo_defs_table[idx]; - def->sd_un = sd_un; - /* Defer running callback until all early defaults are set. */ - early->run_callback = true; - debug_return_bool(true); + if (parse_default_entry(def, val, op, &def->sd_un, file, lineno, quiet)) { + early->run_callback = true; + debug_return_bool(true); + } } debug_return_bool(false); } @@ -407,17 +418,17 @@ run_early_defaults(void) } static void -free_default(struct sudo_defs_types *def) +free_default(int type, union sudo_defs_val *sd_un) { - switch (def->type & T_MASK) { + switch (type & T_MASK) { case T_STR: - free(def->sd_un.str); + free(sd_un->str); break; case T_LIST: - (void)list_op(NULL, 0, &def->sd_un, freeall); + (void)list_op(NULL, 0, sd_un, freeall); break; } - memset(&def->sd_un, 0, sizeof(def->sd_un)); + memset(sd_un, 0, sizeof(*sd_un)); } /* @@ -434,7 +445,7 @@ init_defaults(void) /* Clear any old settings. */ if (!firsttime) { for (def = sudo_defs_table; def->name != NULL; def++) - free_default(def); + free_default(def->type, &def->sd_un); } /* First initialize the flags. */ @@ -692,7 +703,7 @@ update_defaults(int what, bool quiet) * First apply Defaults values marked as early. */ TAILQ_FOREACH(d, &defaults, entries) { - struct early_default *early = is_early_default(d->idx); + struct early_default *early = is_early_default(d->var); if (early == NULL) continue; @@ -702,8 +713,9 @@ update_defaults(int what, bool quiet) continue; /* Copy the value to sudo_defs_table and mark as early. */ - sudo_defs_table[d->idx].sd_un = d->sd_un; - early->run_callback = true; + if (!set_early_default(d->var, d->val, d->op, d->file, d->lineno, + quiet, early)) + ret = false; } /* Run callbacks for early defaults (if any) */ if (!run_early_defaults()) @@ -714,7 +726,7 @@ update_defaults(int what, bool quiet) */ TAILQ_FOREACH(d, &defaults, entries) { /* Skip Defaults marked as early, we already did them. */ - if (is_early_default(d->idx)) + if (is_early_default(d->var)) continue; /* Defaults type and binding must match. */ @@ -723,42 +735,40 @@ update_defaults(int what, bool quiet) continue; /* Copy the value to sudo_defs_table and run callback (if any) */ - sudo_defs_table[d->idx].sd_un = d->sd_un; - if (!run_callback(&sudo_defs_table[d->idx])) + if (!set_default(d->var, d->val, d->op, d->file, d->lineno, quiet)) ret = false; } debug_return_bool(ret); } /* - * Parse a defaults entry, storing the parsed entry in sd_un. - * Returns the matching sudo_defs_table[] index on success or -1 on failure. + * Check all defaults entries without actually setting them. */ -int -parse_default(const char *var, const char *val, int op, - union sudo_defs_val *sd_un, const char *file, int lineno, bool quiet) +bool +check_defaults(bool quiet) { - int i; - debug_decl(parse_default, SUDOERS_DEBUG_DEFAULTS) + struct defaults *d; + bool ret = true; + int idx; + debug_decl(check_defaults, SUDOERS_DEBUG_DEFAULTS) - for (i = 0; sudo_defs_table[i].name != NULL; i++) { - if (strcmp(var, sudo_defs_table[i].name) == 0) { - if (parse_default_entry(&sudo_defs_table[i], val, op, - sd_un, file, lineno, quiet)) - debug_return_int(i); - debug_return_int(-1); - } - } - if (!quiet) { - if (lineno > 0) { - sudo_warnx(U_("%s:%d unknown defaults entry \"%s\""), - file, lineno, var); - } else { - sudo_warnx(U_("%s: unknown defaults entry \"%s\""), - file, var); + TAILQ_FOREACH(d, &defaults, entries) { + idx = find_default(d->var, d->file, d->lineno, quiet); + if (idx != -1) { + struct sudo_defs_types *def = &sudo_defs_table[idx]; + union sudo_defs_val sd_un; + memset(&sd_un, 0, sizeof(sd_un)); + if (parse_default_entry(def, d->val, d->op, &sd_un, d->file, + d->lineno, quiet)) { + free_default(def->type, &sd_un); + continue; + } } + /* There was an error in the entry, flag it. */ + d->error = true; + ret = false; } - debug_return_int(-1); + debug_return_bool(ret); } static bool diff --git a/plugins/sudoers/defaults.h b/plugins/sudoers/defaults.h index 1b0d1db85..163d3c64d 100644 --- a/plugins/sudoers/defaults.h +++ b/plugins/sudoers/defaults.h @@ -121,13 +121,12 @@ struct early_default { */ void dump_default(void); bool init_defaults(void); -struct early_default *is_early_default(int idx); -struct early_default *is_early_default_byname(const char *name); +struct early_default *is_early_default(const char *name); bool run_early_defaults(void); bool set_early_default(const char *var, const char *val, int op, const char *file, int lineno, bool quiet, struct early_default *early); bool set_default(const char *var, const char *val, int op, const char *file, int lineno, bool quiet); bool update_defaults(int what, bool quiet); -int parse_default(const char *var, const char *val, int op, union sudo_defs_val *sd_un, const char *file, int lineno, bool quiet); +bool check_defaults(bool quiet); extern struct sudo_defs_types sudo_defs_table[]; diff --git a/plugins/sudoers/gram.c b/plugins/sudoers/gram.c index 917fd495c..ef2b279c1 100644 --- a/plugins/sudoers/gram.c +++ b/plugins/sudoers/gram.c @@ -91,7 +91,6 @@ * Globals */ bool sudoers_warnings = true; -bool allow_unknown_defaults = true; bool parse_error = false; int errorlineno = -1; char *errorfile = NULL; @@ -104,10 +103,10 @@ struct userspec_list userspecs = TAILQ_HEAD_INITIALIZER(userspecs); */ static bool add_defaults(int, struct member *, struct defaults *); static bool add_userspec(struct member *, struct privilege *); -static struct defaults *new_default(char *, char *, int); +static struct defaults *new_default(char *, char *, short); static struct member *new_member(char *, int); static struct sudo_digest *new_digest(int, const char *); -#line 74 "gram.y" +#line 73 "gram.y" #ifndef YYSTYPE_DEFINED #define YYSTYPE_DEFINED typedef union { @@ -125,7 +124,7 @@ typedef union { int tok; } YYSTYPE; #endif /* YYSTYPE_DEFINED */ -#line 128 "gram.c" +#line 127 "gram.c" #define COMMAND 257 #define ALIAS 258 #define DEFVAR 259 @@ -690,7 +689,7 @@ short *yysslim; YYSTYPE *yyvs; unsigned int yystacksize; int yyparse(void); -#line 850 "gram.y" +#line 849 "gram.y" void sudoerserror(const char *s) { @@ -728,7 +727,7 @@ sudoerserror(const char *s) } static struct defaults * -new_default(char *var, char *val, int op) +new_default(char *var, char *val, short op) { struct defaults *d; debug_decl(new_default, SUDOERS_DEBUG_PARSER) @@ -744,6 +743,14 @@ new_default(char *var, char *val, int op) /* d->type = 0; */ d->op = op; /* d->binding = NULL */ + d->lineno = last_token == COMMENT ? sudolineno - 1 : sudolineno; + d->file = strdup(sudoers); + if (d->file == NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "unable to allocate memory"); + free(d); + debug_return_ptr(NULL); + } HLTQ_INIT(d, entries); debug_return_ptr(d); @@ -802,7 +809,6 @@ add_defaults(int type, struct member *bmem, struct defaults *defs) { struct defaults *d, *next; struct member_list *binding; - bool binding_used = false; bool ret = true; debug_decl(add_defaults, SUDOERS_DEBUG_PARSER) @@ -823,33 +829,12 @@ add_defaults(int type, struct member *bmem, struct defaults *defs) /* * Set type and binding (who it applies to) for new entries. - * Then add to the global defaults list if it parses. + * Then add to the global defaults list. */ HLTQ_FOREACH_SAFE(d, defs, entries, next) { - d->idx = parse_default(d->var, d->val, d->op, &d->sd_un, - sudoers, sudolineno, !sudoers_warnings); - if (d->idx != -1) { - /* Append to defaults list */ - d->type = type; - d->binding = binding; - binding_used = true; - TAILQ_INSERT_TAIL(&defaults, d, entries); - } else { - /* Did not parse */ - if (ret && !allow_unknown_defaults) { - sudoerserror(NULL); - ret = false; - } - free(d->var); - free(d->val); - free(d); - } - } - - if (!binding_used) { - /* No valid Defaults entries, binding unused. */ - free_members(binding); - free(binding); + d->type = type; + d->binding = binding; + TAILQ_INSERT_TAIL(&defaults, d, entries); } } @@ -903,7 +888,7 @@ free_members(struct member_list *members) * the current sudoers file to path. */ bool -init_parser(const char *path, bool quiet, bool strict_defaults) +init_parser(const char *path, bool quiet) { struct member_list *binding; struct defaults *d, *d_next; @@ -999,6 +984,7 @@ init_parser(const char *path, bool quiet, bool strict_defaults) /* no need to free sd_un */ free(d->var); free(d->val); + free(d->file); free(d); } TAILQ_INIT(&defaults); @@ -1025,11 +1011,10 @@ init_parser(const char *path, bool quiet, bool strict_defaults) free(errorfile); errorfile = NULL; sudoers_warnings = !quiet; - allow_unknown_defaults = !strict_defaults; debug_return_bool(ret); } -#line 980 "gram.c" +#line 965 "gram.c" /* allocate initial stack or double stack size, up to YYMAXDEPTH */ #if defined(__cplusplus) || defined(__STDC__) static int yygrowstack(void) @@ -1238,23 +1223,23 @@ yyreduce: switch (yyn) { case 1: -#line 168 "gram.y" +#line 167 "gram.y" { ; } break; case 5: -#line 176 "gram.y" +#line 175 "gram.y" { ; } break; case 6: -#line 179 "gram.y" +#line 178 "gram.y" { yyerrok; } break; case 7: -#line 182 "gram.y" +#line 181 "gram.y" { if (!add_userspec(yyvsp[-1].member, yyvsp[0].privilege)) { sudoerserror(N_("unable to allocate memory")); @@ -1263,73 +1248,73 @@ case 7: } break; case 8: -#line 188 "gram.y" +#line 187 "gram.y" { ; } break; case 9: -#line 191 "gram.y" +#line 190 "gram.y" { ; } break; case 10: -#line 194 "gram.y" +#line 193 "gram.y" { ; } break; case 11: -#line 197 "gram.y" +#line 196 "gram.y" { ; } break; case 12: -#line 200 "gram.y" +#line 199 "gram.y" { if (!add_defaults(DEFAULTS, NULL, yyvsp[0].defaults)) YYERROR; } break; case 13: -#line 204 "gram.y" +#line 203 "gram.y" { if (!add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; case 14: -#line 208 "gram.y" +#line 207 "gram.y" { if (!add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; case 15: -#line 212 "gram.y" +#line 211 "gram.y" { if (!add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; case 16: -#line 216 "gram.y" +#line 215 "gram.y" { if (!add_defaults(DEFAULTS_CMND, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; case 18: -#line 223 "gram.y" +#line 222 "gram.y" { HLTQ_CONCAT(yyvsp[-2].defaults, yyvsp[0].defaults, entries); yyval.defaults = yyvsp[-2].defaults; } break; case 19: -#line 229 "gram.y" +#line 228 "gram.y" { yyval.defaults = new_default(yyvsp[0].string, NULL, true); if (yyval.defaults == NULL) { @@ -1339,7 +1324,7 @@ case 19: } break; case 20: -#line 236 "gram.y" +#line 235 "gram.y" { yyval.defaults = new_default(yyvsp[0].string, NULL, false); if (yyval.defaults == NULL) { @@ -1349,7 +1334,7 @@ case 20: } break; case 21: -#line 243 "gram.y" +#line 242 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, true); if (yyval.defaults == NULL) { @@ -1359,7 +1344,7 @@ case 21: } break; case 22: -#line 250 "gram.y" +#line 249 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '+'); if (yyval.defaults == NULL) { @@ -1369,7 +1354,7 @@ case 22: } break; case 23: -#line 257 "gram.y" +#line 256 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '-'); if (yyval.defaults == NULL) { @@ -1379,14 +1364,14 @@ case 23: } break; case 25: -#line 267 "gram.y" +#line 266 "gram.y" { HLTQ_CONCAT(yyvsp[-2].privilege, yyvsp[0].privilege, entries); yyval.privilege = yyvsp[-2].privilege; } break; case 26: -#line 273 "gram.y" +#line 272 "gram.y" { struct privilege *p = calloc(1, sizeof(*p)); if (p == NULL) { @@ -1400,21 +1385,21 @@ case 26: } break; case 27: -#line 286 "gram.y" +#line 285 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; case 28: -#line 290 "gram.y" +#line 289 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; case 29: -#line 296 "gram.y" +#line 295 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -1424,7 +1409,7 @@ case 29: } break; case 30: -#line 303 "gram.y" +#line 302 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -1434,7 +1419,7 @@ case 30: } break; case 31: -#line 310 "gram.y" +#line 309 "gram.y" { yyval.member = new_member(yyvsp[0].string, NETGROUP); if (yyval.member == NULL) { @@ -1444,7 +1429,7 @@ case 31: } break; case 32: -#line 317 "gram.y" +#line 316 "gram.y" { yyval.member = new_member(yyvsp[0].string, NTWKADDR); if (yyval.member == NULL) { @@ -1454,7 +1439,7 @@ case 32: } break; case 33: -#line 324 "gram.y" +#line 323 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); if (yyval.member == NULL) { @@ -1464,7 +1449,7 @@ case 33: } break; case 35: -#line 334 "gram.y" +#line 333 "gram.y" { struct cmndspec *prev; prev = HLTQ_LAST(yyvsp[-2].cmndspec, cmndspec, entries); @@ -1510,7 +1495,7 @@ case 35: } break; case 36: -#line 379 "gram.y" +#line 378 "gram.y" { struct cmndspec *cs = calloc(1, sizeof(*cs)); if (cs == NULL) { @@ -1559,7 +1544,7 @@ case 36: } break; case 37: -#line 427 "gram.y" +#line 426 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA224, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1569,7 +1554,7 @@ case 37: } break; case 38: -#line 434 "gram.y" +#line 433 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA256, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1579,7 +1564,7 @@ case 38: } break; case 39: -#line 441 "gram.y" +#line 440 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA384, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1589,7 +1574,7 @@ case 39: } break; case 40: -#line 448 "gram.y" +#line 447 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA512, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1599,13 +1584,13 @@ case 40: } break; case 41: -#line 457 "gram.y" +#line 456 "gram.y" { yyval.member = yyvsp[0].member; } break; case 42: -#line 460 "gram.y" +#line 459 "gram.y" { if (yyvsp[0].member->type != COMMAND) { sudoerserror(N_("a digest requires a path name")); @@ -1617,127 +1602,127 @@ case 42: } break; case 43: -#line 471 "gram.y" +#line 470 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; case 44: -#line 475 "gram.y" +#line 474 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; case 45: -#line 481 "gram.y" +#line 480 "gram.y" { yyval.string = yyvsp[0].string; } break; case 46: -#line 486 "gram.y" +#line 485 "gram.y" { yyval.string = yyvsp[0].string; } break; case 47: -#line 491 "gram.y" +#line 490 "gram.y" { yyval.seinfo.role = NULL; yyval.seinfo.type = NULL; } break; case 48: -#line 495 "gram.y" +#line 494 "gram.y" { yyval.seinfo.role = yyvsp[0].string; yyval.seinfo.type = NULL; } break; case 49: -#line 499 "gram.y" +#line 498 "gram.y" { yyval.seinfo.type = yyvsp[0].string; yyval.seinfo.role = NULL; } break; case 50: -#line 503 "gram.y" +#line 502 "gram.y" { yyval.seinfo.role = yyvsp[-1].string; yyval.seinfo.type = yyvsp[0].string; } break; case 51: -#line 507 "gram.y" +#line 506 "gram.y" { yyval.seinfo.type = yyvsp[-1].string; yyval.seinfo.role = yyvsp[0].string; } break; case 52: -#line 513 "gram.y" +#line 512 "gram.y" { yyval.string = yyvsp[0].string; } break; case 53: -#line 517 "gram.y" +#line 516 "gram.y" { yyval.string = yyvsp[0].string; } break; case 54: -#line 522 "gram.y" +#line 521 "gram.y" { yyval.privinfo.privs = NULL; yyval.privinfo.limitprivs = NULL; } break; case 55: -#line 526 "gram.y" +#line 525 "gram.y" { yyval.privinfo.privs = yyvsp[0].string; yyval.privinfo.limitprivs = NULL; } break; case 56: -#line 530 "gram.y" +#line 529 "gram.y" { yyval.privinfo.privs = NULL; yyval.privinfo.limitprivs = yyvsp[0].string; } break; case 57: -#line 534 "gram.y" +#line 533 "gram.y" { yyval.privinfo.privs = yyvsp[-1].string; yyval.privinfo.limitprivs = yyvsp[0].string; } break; case 58: -#line 538 "gram.y" +#line 537 "gram.y" { yyval.privinfo.limitprivs = yyvsp[-1].string; yyval.privinfo.privs = yyvsp[0].string; } break; case 59: -#line 544 "gram.y" +#line 543 "gram.y" { yyval.runas = NULL; } break; case 60: -#line 547 "gram.y" +#line 546 "gram.y" { yyval.runas = yyvsp[-1].runas; } break; case 61: -#line 552 "gram.y" +#line 551 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas != NULL) { @@ -1755,7 +1740,7 @@ case 61: } break; case 62: -#line 567 "gram.y" +#line 566 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas == NULL) { @@ -1767,7 +1752,7 @@ case 62: } break; case 63: -#line 576 "gram.y" +#line 575 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas == NULL) { @@ -1779,7 +1764,7 @@ case 63: } break; case 64: -#line 585 "gram.y" +#line 584 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas == NULL) { @@ -1791,7 +1776,7 @@ case 64: } break; case 65: -#line 594 "gram.y" +#line 593 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas != NULL) { @@ -1809,97 +1794,97 @@ case 65: } break; case 66: -#line 611 "gram.y" +#line 610 "gram.y" { TAGS_INIT(yyval.tag); } break; case 67: -#line 614 "gram.y" +#line 613 "gram.y" { yyval.tag.nopasswd = true; } break; case 68: -#line 617 "gram.y" +#line 616 "gram.y" { yyval.tag.nopasswd = false; } break; case 69: -#line 620 "gram.y" +#line 619 "gram.y" { yyval.tag.noexec = true; } break; case 70: -#line 623 "gram.y" +#line 622 "gram.y" { yyval.tag.noexec = false; } break; case 71: -#line 626 "gram.y" +#line 625 "gram.y" { yyval.tag.setenv = true; } break; case 72: -#line 629 "gram.y" +#line 628 "gram.y" { yyval.tag.setenv = false; } break; case 73: -#line 632 "gram.y" +#line 631 "gram.y" { yyval.tag.log_input = true; } break; case 74: -#line 635 "gram.y" +#line 634 "gram.y" { yyval.tag.log_input = false; } break; case 75: -#line 638 "gram.y" +#line 637 "gram.y" { yyval.tag.log_output = true; } break; case 76: -#line 641 "gram.y" +#line 640 "gram.y" { yyval.tag.log_output = false; } break; case 77: -#line 644 "gram.y" +#line 643 "gram.y" { yyval.tag.follow = true; } break; case 78: -#line 647 "gram.y" +#line 646 "gram.y" { yyval.tag.follow = false; } break; case 79: -#line 650 "gram.y" +#line 649 "gram.y" { yyval.tag.send_mail = true; } break; case 80: -#line 653 "gram.y" +#line 652 "gram.y" { yyval.tag.send_mail = false; } break; case 81: -#line 658 "gram.y" +#line 657 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -1909,7 +1894,7 @@ case 81: } break; case 82: -#line 665 "gram.y" +#line 664 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -1919,7 +1904,7 @@ case 82: } break; case 83: -#line 672 "gram.y" +#line 671 "gram.y" { struct sudo_command *c = calloc(1, sizeof(*c)); if (c == NULL) { @@ -1937,7 +1922,7 @@ case 83: } break; case 86: -#line 693 "gram.y" +#line 692 "gram.y" { const char *s; if ((s = alias_add(yyvsp[-2].string, HOSTALIAS, yyvsp[0].member)) != NULL) { @@ -1947,14 +1932,14 @@ case 86: } break; case 88: -#line 703 "gram.y" +#line 702 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; case 91: -#line 713 "gram.y" +#line 712 "gram.y" { const char *s; if ((s = alias_add(yyvsp[-2].string, CMNDALIAS, yyvsp[0].member)) != NULL) { @@ -1964,14 +1949,14 @@ case 91: } break; case 93: -#line 723 "gram.y" +#line 722 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; case 96: -#line 733 "gram.y" +#line 732 "gram.y" { const char *s; if ((s = alias_add(yyvsp[-2].string, RUNASALIAS, yyvsp[0].member)) != NULL) { @@ -1981,7 +1966,7 @@ case 96: } break; case 99: -#line 746 "gram.y" +#line 745 "gram.y" { const char *s; if ((s = alias_add(yyvsp[-2].string, USERALIAS, yyvsp[0].member)) != NULL) { @@ -1991,28 +1976,28 @@ case 99: } break; case 101: -#line 756 "gram.y" +#line 755 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; case 102: -#line 762 "gram.y" +#line 761 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; case 103: -#line 766 "gram.y" +#line 765 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; case 104: -#line 772 "gram.y" +#line 771 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -2022,7 +2007,7 @@ case 104: } break; case 105: -#line 779 "gram.y" +#line 778 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -2032,7 +2017,7 @@ case 105: } break; case 106: -#line 786 "gram.y" +#line 785 "gram.y" { yyval.member = new_member(yyvsp[0].string, NETGROUP); if (yyval.member == NULL) { @@ -2042,7 +2027,7 @@ case 106: } break; case 107: -#line 793 "gram.y" +#line 792 "gram.y" { yyval.member = new_member(yyvsp[0].string, USERGROUP); if (yyval.member == NULL) { @@ -2052,7 +2037,7 @@ case 107: } break; case 108: -#line 800 "gram.y" +#line 799 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); if (yyval.member == NULL) { @@ -2062,28 +2047,28 @@ case 108: } break; case 110: -#line 810 "gram.y" +#line 809 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; case 111: -#line 816 "gram.y" +#line 815 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; case 112: -#line 820 "gram.y" +#line 819 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; case 113: -#line 826 "gram.y" +#line 825 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -2093,7 +2078,7 @@ case 113: } break; case 114: -#line 833 "gram.y" +#line 832 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -2103,7 +2088,7 @@ case 114: } break; case 115: -#line 840 "gram.y" +#line 839 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); if (yyval.member == NULL) { @@ -2112,7 +2097,7 @@ case 115: } } break; -#line 2063 "gram.c" +#line 2048 "gram.c" } yyssp -= yym; yystate = *yyssp; diff --git a/plugins/sudoers/gram.y b/plugins/sudoers/gram.y index 145b9f527..70e24f78e 100644 --- a/plugins/sudoers/gram.y +++ b/plugins/sudoers/gram.y @@ -53,7 +53,6 @@ * Globals */ bool sudoers_warnings = true; -bool allow_unknown_defaults = true; bool parse_error = false; int errorlineno = -1; char *errorfile = NULL; @@ -66,7 +65,7 @@ struct userspec_list userspecs = TAILQ_HEAD_INITIALIZER(userspecs); */ static bool add_defaults(int, struct member *, struct defaults *); static bool add_userspec(struct member *, struct privilege *); -static struct defaults *new_default(char *, char *, int); +static struct defaults *new_default(char *, char *, short); static struct member *new_member(char *, int); static struct sudo_digest *new_digest(int, const char *); %} @@ -884,7 +883,7 @@ sudoerserror(const char *s) } static struct defaults * -new_default(char *var, char *val, int op) +new_default(char *var, char *val, short op) { struct defaults *d; debug_decl(new_default, SUDOERS_DEBUG_PARSER) @@ -900,6 +899,14 @@ new_default(char *var, char *val, int op) /* d->type = 0; */ d->op = op; /* d->binding = NULL */ + d->lineno = last_token == COMMENT ? sudolineno - 1 : sudolineno; + d->file = strdup(sudoers); + if (d->file == NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "unable to allocate memory"); + free(d); + debug_return_ptr(NULL); + } HLTQ_INIT(d, entries); debug_return_ptr(d); @@ -958,7 +965,6 @@ add_defaults(int type, struct member *bmem, struct defaults *defs) { struct defaults *d, *next; struct member_list *binding; - bool binding_used = false; bool ret = true; debug_decl(add_defaults, SUDOERS_DEBUG_PARSER) @@ -979,33 +985,12 @@ add_defaults(int type, struct member *bmem, struct defaults *defs) /* * Set type and binding (who it applies to) for new entries. - * Then add to the global defaults list if it parses. + * Then add to the global defaults list. */ HLTQ_FOREACH_SAFE(d, defs, entries, next) { - d->idx = parse_default(d->var, d->val, d->op, &d->sd_un, - sudoers, sudolineno, !sudoers_warnings); - if (d->idx != -1) { - /* Append to defaults list */ - d->type = type; - d->binding = binding; - binding_used = true; - TAILQ_INSERT_TAIL(&defaults, d, entries); - } else { - /* Did not parse */ - if (ret && !allow_unknown_defaults) { - sudoerserror(NULL); - ret = false; - } - free(d->var); - free(d->val); - free(d); - } - } - - if (!binding_used) { - /* No valid Defaults entries, binding unused. */ - free_members(binding); - free(binding); + d->type = type; + d->binding = binding; + TAILQ_INSERT_TAIL(&defaults, d, entries); } } @@ -1059,7 +1044,7 @@ free_members(struct member_list *members) * the current sudoers file to path. */ bool -init_parser(const char *path, bool quiet, bool strict_defaults) +init_parser(const char *path, bool quiet) { struct member_list *binding; struct defaults *d, *d_next; @@ -1155,6 +1140,7 @@ init_parser(const char *path, bool quiet, bool strict_defaults) /* no need to free sd_un */ free(d->var); free(d->val); + free(d->file); free(d); } TAILQ_INIT(&defaults); @@ -1181,7 +1167,6 @@ init_parser(const char *path, bool quiet, bool strict_defaults) free(errorfile); errorfile = NULL; sudoers_warnings = !quiet; - allow_unknown_defaults = !strict_defaults; debug_return_bool(ret); } diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c index b1d1116f9..db38b7363 100644 --- a/plugins/sudoers/ldap.c +++ b/plugins/sudoers/ldap.c @@ -1162,7 +1162,7 @@ sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry) goto done; } op = sudo_ldap_parse_option(copy, &var, &val); - early = is_early_default_byname(var); + early = is_early_default(var); if (early != NULL) { set_early_default(var, val, op, source ? source : "sudoRole UNKNOWN", 0, false, early); @@ -1178,7 +1178,7 @@ sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry) goto done; } op = sudo_ldap_parse_option(copy, &var, &val); - if (is_early_default_byname(var) == NULL) { + if (is_early_default(var) == NULL) { set_default(var, val, op, source ? source : "sudoRole UNKNOWN", 0, false); } diff --git a/plugins/sudoers/parse.c b/plugins/sudoers/parse.c index 5e8236741..08474a504 100644 --- a/plugins/sudoers/parse.c +++ b/plugins/sudoers/parse.c @@ -87,7 +87,7 @@ sudo_file_close(struct sudo_nss *nss) debug_decl(sudo_file_close, SUDOERS_DEBUG_NSS) /* Free parser data structures and close sudoers file. */ - init_parser(NULL, false, false); + init_parser(NULL, false); if (nss->handle != NULL) { fclose(nss->handle); nss->handle = NULL; @@ -107,7 +107,7 @@ sudo_file_parse(struct sudo_nss *nss) if (nss->handle == NULL) debug_return_int(-1); - init_parser(sudoers_file, false, false); + init_parser(sudoers_file, false); sudoersin = nss->handle; if (sudoersparse() != 0 || parse_error) { if (errorlineno != -1) { diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h index 74eeb4c7f..684dfeedf 100644 --- a/plugins/sudoers/parse.h +++ b/plugins/sudoers/parse.h @@ -221,10 +221,11 @@ struct defaults { char *var; /* variable name */ char *val; /* variable value */ struct member_list *binding; /* user/host/runas binding */ - int type; /* DEFAULTS{,_USER,_RUNAS,_HOST} */ - int op; /* true, false, '+', '-' */ - int idx; /* index into sudo_defs_table */ - union sudo_defs_val sd_un; /* parsed value */ + char *file; /* file Defaults entry was in */ + short type; /* DEFAULTS{,_USER,_RUNAS,_HOST} */ + char op; /* true, false, '+', '-' */ + char error; /* parse error flag */ + int lineno; /* line number of Defaults entry */ }; /* @@ -245,7 +246,7 @@ void alias_put(struct alias *a); bool init_aliases(void); /* gram.c */ -bool init_parser(const char *path, bool quiet, bool strict_defaults); +bool init_parser(const char *path, bool quiet); void free_members(struct member_list *members); /* match_addr.c */ diff --git a/plugins/sudoers/regress/parser/check_fill.c b/plugins/sudoers/regress/parser/check_fill.c index 65363d98c..c731d04f3 100644 --- a/plugins/sudoers/regress/parser/check_fill.c +++ b/plugins/sudoers/regress/parser/check_fill.c @@ -37,7 +37,6 @@ #include "sudo_compat.h" #include "sudo_queue.h" -#include "defaults.h" #include "parse.h" #include "toke.h" #include "sudo_plugin.h" diff --git a/plugins/sudoers/sssd.c b/plugins/sudoers/sssd.c index f088b18bb..a01516576 100644 --- a/plugins/sudoers/sssd.c +++ b/plugins/sudoers/sssd.c @@ -1242,7 +1242,7 @@ sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rul goto done; } op = sudo_sss_parse_option(copy, &var, &val); - early = is_early_default_byname(var); + early = is_early_default(var); if (early != NULL) { set_early_default(var, val, op, source ? source : "sudoRole UNKNOWN", 0, false, early); @@ -1258,7 +1258,7 @@ sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rul goto done; } op = sudo_sss_parse_option(copy, &var, &val); - if (is_early_default_byname(var) == NULL) { + if (is_early_default(var) == NULL) { set_default(var, val, op, source ? source : "sudoRole UNKNOWN", 0, false); } diff --git a/plugins/sudoers/testsudoers.c b/plugins/sudoers/testsudoers.c index 519568a83..30e092320 100644 --- a/plugins/sudoers/testsudoers.c +++ b/plugins/sudoers/testsudoers.c @@ -261,7 +261,7 @@ main(int argc, char *argv[]) } /* Allocate space for data structures in the parser. */ - init_parser("sudoers", false, true); + init_parser("sudoers", false); /* * Set runas passwd/group entries based on command line or sudoers. diff --git a/plugins/sudoers/visudo.c b/plugins/sudoers/visudo.c index 7018f5e9e..f33c1db34 100644 --- a/plugins/sudoers/visudo.c +++ b/plugins/sudoers/visudo.c @@ -245,7 +245,7 @@ main(int argc, char *argv[]) */ if ((sudoersin = open_sudoers(sudoers_file, true, NULL)) == NULL) exit(1); - init_parser(sudoers_file, quiet, true); + init_parser(sudoers_file, quiet); sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); (void) sudoersparse(); (void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, quiet); @@ -551,6 +551,39 @@ done: debug_return_bool(ret); } +/* + * Check Defaults and Alias entries. + * Sets parse_error on error and errorfile/errorlineno if possible. + */ +static void +check_defaults_and_aliases(bool strict, bool quiet) +{ + debug_decl(check_defaults_and_aliases, SUDOERS_DEBUG_UTIL) + + if (!check_defaults(quiet)) { + struct defaults *d; + free(errorfile); + errorfile = NULL; + /* XXX - should edit all files with errors */ + TAILQ_FOREACH(d, &defaults, entries) { + if (d->error) { + /* Defaults parse error, adopt the file name. */ + errorfile = d->file; + errorlineno = d->lineno; + d->file = NULL; + d->error = false; /* paranoia */ + break; + } + } + parse_error = true; + } else if (check_aliases(strict, quiet) != 0) { + free(errorfile); + errorfile = NULL; /* don't know which file */ + parse_error = true; + } + debug_return; +} + /* * Parse sudoers after editing and re-edit any ones that caused a parse error. */ @@ -576,7 +609,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, true); + init_parser(sp->path, quiet); /* Parse the sudoers temp file(s) */ sudoersrestart(fp); @@ -592,11 +625,7 @@ reparse_sudoers(char *editor, int editor_argc, char **editor_argv, fclose(sudoersin); if (!parse_error) { (void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, true); - if (check_aliases(strict, quiet) != 0) { - parse_error = true; - free(errorfile); - errorfile = NULL; /* don't know which file */ - } + check_defaults_and_aliases(strict, quiet); } sudoers_setlocale(oldlocale, NULL); @@ -924,7 +953,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, true); + init_parser(sudoers_file, quiet); sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); if (sudoersparse() && !parse_error) { if (!quiet) @@ -936,11 +965,7 @@ check_syntax(const char *sudoers_file, bool quiet, bool strict, bool oldperms) } if (!parse_error) { (void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, true); - if (check_aliases(strict, quiet) != 0) { - parse_error = true; - free(errorfile); - errorfile = NULL; /* don't know which file */ - } + check_defaults_and_aliases(strict, quiet); } sudoers_setlocale(oldlocale, NULL); ok = !parse_error; diff --git a/plugins/sudoers/visudo_json.c b/plugins/sudoers/visudo_json.c index 96bf93138..dd2ced273 100644 --- a/plugins/sudoers/visudo_json.c +++ b/plugins/sudoers/visudo_json.c @@ -1025,7 +1025,7 @@ export_sudoers(const char *sudoers_path, const char *export_path, goto done; } } - init_parser(sudoers_path, quiet, true); + init_parser(sudoers_path, quiet); if (sudoersparse() && !parse_error) { if (!quiet) sudo_warnx(U_("failed to parse %s file, unknown error"), sudoers_path);