From 75e29f163e3f2ffb92e3da76eee3ac65bd6a1427 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Wed, 2 Nov 2016 17:07:32 -0600 Subject: [PATCH] Add file:linenumber prefix to all Defaults warnings so we can see them when running sudo too. For LDAP/SSSD we print the sudoRole instead of the file name and omit the line number. --- plugins/sudoers/defaults.c | 122 +++++++++++++++++++++++++++---------- plugins/sudoers/defaults.h | 6 +- plugins/sudoers/gram.c | 6 +- plugins/sudoers/gram.y | 6 +- plugins/sudoers/ldap.c | 28 +++++++-- plugins/sudoers/sssd.c | 30 +++++++-- 6 files changed, 146 insertions(+), 52 deletions(-) diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c index 3faeff860..1d1aea07c 100644 --- a/plugins/sudoers/defaults.c +++ b/plugins/sudoers/defaults.c @@ -90,6 +90,10 @@ static struct early_default early_defaults[] = { { NULL } }; +/* Flags for set_default_entry() and set_default_int() */ +#define FLAG_DO_CALLBACK 0x01 +#define FLAG_QUIET 0x02 + /* * Local prototypes. */ @@ -193,7 +197,7 @@ dump_defaults(void) static bool set_default_entry(struct sudo_defs_types *def, const char *val, int op, - bool quiet, bool do_callback) + const char *file, int lineno, int flags) { int rc; debug_decl(set_default_entry, SUDOERS_DEBUG_DEFAULTS) @@ -201,8 +205,15 @@ set_default_entry(struct sudo_defs_types *def, const char *val, int op, if (val == NULL && !ISSET(def->type, T_FLAG)) { /* Check for bogus boolean usage or missing value if non-boolean. */ if (!ISSET(def->type, T_BOOL) || op != false) { - if (!quiet) - sudo_warnx(U_("no value specified for `%s'"), def->name); + if (!ISSET(flags, FLAG_QUIET)) { + if (lineno > 0) { + sudo_warnx(U_("%s:%d no value specified for `%s'"), + file, lineno, def->name); + } else { + sudo_warnx(U_("%s: no value specified for `%s'"), + file, def->name); + } + } debug_return_bool(false); } } @@ -216,9 +227,14 @@ set_default_entry(struct sudo_defs_types *def, const char *val, int op, break; case T_STR: if (ISSET(def->type, T_PATH) && val != NULL && *val != '/') { - if (!quiet) { - sudo_warnx(U_("values for `%s' must start with a '/'"), - def->name); + if (!ISSET(flags, FLAG_QUIET)) { + if (lineno > 0) { + sudo_warnx(U_("%s:%d values for `%s' must start with a '/'"), + file, lineno, def->name); + } else { + sudo_warnx(U_("%s: values for `%s' must start with a '/'"), + file, def->name); + } } rc = -1; break; @@ -239,9 +255,14 @@ set_default_entry(struct sudo_defs_types *def, const char *val, int op, break; case T_FLAG: if (val != NULL) { - if (!quiet) { - sudo_warnx(U_("option `%s' does not take a value"), - def->name); + if (!ISSET(flags, FLAG_QUIET)) { + if (lineno > 0) { + sudo_warnx(U_("%s:%d option `%s' does not take a value"), + file, lineno, def->name); + } else { + sudo_warnx(U_("%s: option `%s' does not take a value"), + file, def->name); + } } rc = -1; break; @@ -256,9 +277,14 @@ set_default_entry(struct sudo_defs_types *def, const char *val, int op, rc = store_tuple(val, def); break; default: - if (!quiet) { - sudo_warnx(U_("invalid Defaults type 0x%x for option `%s'"), - def->type, def->name); + if (!ISSET(flags, FLAG_QUIET)) { + if (lineno > 0) { + sudo_warnx(U_("%s:%d invalid Defaults type 0x%x for option `%s'"), + file, lineno, def->type, def->name); + } else { + sudo_warnx(U_("%s: invalid Defaults type 0x%x for option `%s'"), + file, def->type, def->name); + } } rc = -1; break; @@ -269,13 +295,18 @@ set_default_entry(struct sudo_defs_types *def, const char *val, int op, rc = false; break; case false: - if (!quiet) { - sudo_warnx(U_("value `%s' is invalid for option `%s'"), - val, def->name); + if (!ISSET(flags, FLAG_QUIET)) { + if (lineno > 0) { + sudo_warnx(U_("%s:%d value `%s' is invalid for option `%s'"), + file, lineno, val, def->name); + } else { + sudo_warnx(U_("%s: value `%s' is invalid for option `%s'"), + file, val, def->name); + } } break; case true: - if (do_callback && def->callback) + if (ISSET(flags, FLAG_DO_CALLBACK) && def->callback) rc = def->callback(&def->sd_un); break; } @@ -304,8 +335,8 @@ is_early_default(const char *var) * This is only meaningful for variables that are *optional*. */ static struct sudo_defs_types * -set_default_int(const char *var, const char *val, int op, bool quiet, - bool do_callback) +set_default_int(const char *var, const char *val, int op, const char *file, + int lineno, int flags) { struct sudo_defs_types *cur; int num; @@ -316,12 +347,19 @@ set_default_int(const char *var, const char *val, int op, bool quiet, break; } if (!cur->name) { - if (!quiet) - sudo_warnx(U_("unknown defaults entry `%s'"), var); + if (!ISSET(flags, FLAG_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); + } + } debug_return_ptr(NULL); } - if (!set_default_entry(cur, val, op, quiet, do_callback)) + if (!set_default_entry(cur, val, op, file, lineno, flags)) debug_return_ptr(NULL); debug_return_ptr(cur); } @@ -331,12 +369,16 @@ set_default_int(const char *var, const char *val, int op, bool quiet, * Runs the callback if present on success. */ bool -set_default(const char *var, const char *val, int op, bool quiet) +set_default(const char *var, const char *val, int op, const char *file, + int lineno, bool quiet) { const struct sudo_defs_types *def; + int flags = FLAG_DO_CALLBACK; debug_decl(set_default, SUDOERS_DEBUG_DEFAULTS) - def = set_default_int(var, val, op, quiet, true); + if (quiet) + SET(flags, FLAG_QUIET); + def = set_default_int(var, val, op, file, lineno, flags); debug_return_bool(def != NULL); } @@ -345,13 +387,16 @@ set_default(const char *var, const char *val, int op, bool quiet) * and does not run callbacks. */ bool -set_early_default(const char *var, const char *val, int op, bool quiet, - struct early_default *early) +set_early_default(const char *var, const char *val, int op, const char *file, + int lineno, bool quiet, struct early_default *early) { const struct sudo_defs_types *def; + int flags = 0; debug_decl(set_early_default, SUDOERS_DEBUG_DEFAULTS) - def = set_default_int(var, val, op, quiet, false); + if (quiet) + SET(flags, FLAG_QUIET); + def = set_default_int(var, val, op, file, lineno, flags); if (def == NULL) debug_return_bool(false); early->def = def; @@ -673,7 +718,7 @@ update_defaults(int what, bool quiet) if (!default_type_matches(def, what) || !default_binding_matches(def, what)) continue; - if (!set_early_default(def->var, def->val, def->op, quiet, early)) + if (!set_early_default(def->var, def->val, def->op, "sudoers", 0, quiet, early)) ret = false; } if (!run_early_defaults()) @@ -690,7 +735,7 @@ update_defaults(int what, bool quiet) if (!default_type_matches(def, what) || !default_binding_matches(def, what)) continue; - if (!set_default(def->var, def->val, def->op, quiet)) + if (!set_default(def->var, def->val, def->op, "sudoers", 0, quiet)) ret = false; } debug_return_bool(ret); @@ -700,26 +745,37 @@ update_defaults(int what, bool quiet) * Check a defaults entry without actually setting it. */ bool -check_default(struct defaults *def, bool quiet) +check_default(const char *var, const char *val, int op, const char *file, + int lineno, bool quiet) { struct sudo_defs_types *cur; bool ret = true; + int flags = 0; debug_decl(check_default, SUDOERS_DEBUG_DEFAULTS) + if (quiet) + SET(flags, FLAG_QUIET); for (cur = sudo_defs_table; cur->name != NULL; cur++) { - if (strcmp(def->var, cur->name) == 0) { + if (strcmp(var, cur->name) == 0) { /* Don't actually set the defaults value, just checking. */ struct sudo_defs_types tmp = *cur; memset(&tmp.sd_un, 0, sizeof(tmp.sd_un)); - if (!set_default_entry(&tmp, def->val, def->op, quiet, false)) + if (!set_default_entry(&tmp, val, op, file, lineno, flags)) ret = false; free_default(&tmp); break; } } if (cur->name == NULL) { - if (!quiet) - sudo_warnx(U_("unknown defaults entry `%s'"), def->var); + 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); + } + } ret = false; } debug_return_bool(ret); diff --git a/plugins/sudoers/defaults.h b/plugins/sudoers/defaults.h index 7a4567d68..55b08b36b 100644 --- a/plugins/sudoers/defaults.h +++ b/plugins/sudoers/defaults.h @@ -122,12 +122,12 @@ struct early_default { struct defaults; /* in parse.h */ void dump_default(void); -bool check_default(struct defaults *def, bool quiet); +bool check_default(const char *var, const char *val, int op, const char *file, int lineno, bool quiet); bool init_defaults(void); struct early_default *is_early_default(const char *var); bool run_early_defaults(void); -bool set_early_default(const char *var, const char *val, int op, bool quiet, struct early_default *early); -bool set_default(const char *var, const char *val, int op, bool quiet); +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); extern struct sudo_defs_types sudo_defs_table[]; diff --git a/plugins/sudoers/gram.c b/plugins/sudoers/gram.c index 29108319e..a87abdedf 100644 --- a/plugins/sudoers/gram.c +++ b/plugins/sudoers/gram.c @@ -826,16 +826,16 @@ add_defaults(int type, struct member *bmem, struct defaults *defs) * Then add to the global defaults list if it parses. */ HLTQ_FOREACH_SAFE(d, defs, entries, next) { - if (check_default(d, !sudoers_warnings)) { + if (check_default(d->var, d->val, d->op, sudoers, sudolineno, !sudoers_warnings)) { /* Append to defaults list */ d->type = type; d->binding = binding; binding_used = true; TAILQ_INSERT_TAIL(&defaults, d, entries); } else { - /* Did not parse, warn and free it. */ + /* Did not parse */ if (!allow_unknown_defaults) { - sudoerserror(N_("problem with defaults entries")); + sudoerserror(NULL); ret = false; } free(d->var); diff --git a/plugins/sudoers/gram.y b/plugins/sudoers/gram.y index e52ddad88..8f5e57d11 100644 --- a/plugins/sudoers/gram.y +++ b/plugins/sudoers/gram.y @@ -982,16 +982,16 @@ add_defaults(int type, struct member *bmem, struct defaults *defs) * Then add to the global defaults list if it parses. */ HLTQ_FOREACH_SAFE(d, defs, entries, next) { - if (check_default(d, !sudoers_warnings)) { + if (check_default(d->var, d->val, d->op, sudoers, sudolineno, !sudoers_warnings)) { /* Append to defaults list */ d->type = type; d->binding = binding; binding_used = true; TAILQ_INSERT_TAIL(&defaults, d, entries); } else { - /* Did not parse, warn and free it. */ + /* Did not parse */ if (!allow_unknown_defaults) { - sudoerserror(N_("problem with defaults entries")); + sudoerserror(NULL); ret = false; } free(d->var); diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c index c85efe2d0..9aa586be4 100644 --- a/plugins/sudoers/ldap.c +++ b/plugins/sudoers/ldap.c @@ -380,6 +380,7 @@ static int sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw, struct sudo_lbuf *lbuf); static struct ldap_result *sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw); +static char *sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry); /* * LDAP sudo_nss handle. @@ -1129,7 +1130,7 @@ static bool sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry) { struct berval **bv, **p; - char *copy, *var, *val; + char *cn, *copy, *var, *val, *source = NULL; bool ret = false; int op; debug_decl(sudo_ldap_parse_options, SUDOERS_DEBUG_LDAP) @@ -1138,6 +1139,16 @@ sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry) if (bv == NULL) debug_return_bool(true); + /* get the entry's dn for option error reporting */ + cn = sudo_ldap_get_first_rdn(ld, entry); + if (cn != NULL) { + if (asprintf(&source, "sudoRole %s", cn) == -1) { + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + source = NULL; + goto done; + } + } + /* walk through options, early ones first */ for (p = bv; *p != NULL; p++) { struct early_default *early; @@ -1148,8 +1159,10 @@ sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry) } op = sudo_ldap_parse_option(copy, &var, &val); early = is_early_default(var); - if (early != NULL) - set_early_default(var, val, op, false, early); + if (early != NULL) { + set_early_default(var, val, op, + source ? source : "sudoRole UNKNOWN", 0, false, early); + } free(copy); } run_early_defaults(); @@ -1161,13 +1174,18 @@ sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry) goto done; } op = sudo_ldap_parse_option(copy, &var, &val); - if (is_early_default(var) == NULL) - set_default(var, val, op, false); + if (is_early_default(var) == NULL) { + set_default(var, val, op, + source ? source : "sudoRole UNKNOWN", 0, false); + } free(copy); } ret = true; done: + free(source); + if (cn) + ldap_memfree(cn); ldap_value_free_len(bv); debug_return_bool(ret); diff --git a/plugins/sudoers/sssd.c b/plugins/sudoers/sssd.c index bb2f139da..c1bf7baf3 100644 --- a/plugins/sudoers/sssd.c +++ b/plugins/sudoers/sssd.c @@ -1196,9 +1196,10 @@ static bool sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule) { int i, op; - char *copy, *var, *val; + char *copy, *var, *val, *source = NULL; bool ret = false; char **val_array = NULL; + char **cn_array = NULL; debug_decl(sudo_sss_parse_options, SUDOERS_DEBUG_SSSD); if (rule == NULL) @@ -1215,6 +1216,20 @@ sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rul debug_return_bool(false); } + /* get the entry's cn for option error reporting */ + if (handle->fn_get_values(rule, "cn", &cn_array) == 0) { + if (cn_array[0] != NULL) { + if (asprintf(&source, "sudoRole %s", cn_array[0]) == -1) { + sudo_warnx(U_("%s: %s"), __func__, + U_("unable to allocate memory")); + source = NULL; + goto done; + } + } + handle->fn_free_values(cn_array); + cn_array = NULL; + } + /* walk through options, early ones first */ for (i = 0; val_array[i] != NULL; i++) { struct early_default *early; @@ -1225,8 +1240,10 @@ sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rul } op = sudo_sss_parse_option(copy, &var, &val); early = is_early_default(var); - if (early != NULL) - set_early_default(var, val, op, false, early); + if (early != NULL) { + set_early_default(var, val, op, + source ? source : "sudoRole UNKNOWN", 0, false, early); + } free(copy); } run_early_defaults(); @@ -1238,13 +1255,16 @@ 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(var) == NULL) - set_default(var, val, op, false); + if (is_early_default(var) == NULL) { + set_default(var, val, op, + source ? source : "sudoRole UNKNOWN", 0, false); + } free(copy); } ret = true; done: + free(source); handle->fn_free_values(val_array); debug_return_bool(ret); } -- 2.40.0