]> granicus.if.org Git - sudo/commitdiff
Instead of parsing sudoers Defaults twice, parse once while reading
authorTodd C. Miller <Todd.Miller@courtesan.com>
Mon, 7 Nov 2016 01:59:49 +0000 (18:59 -0700)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Mon, 7 Nov 2016 01:59:49 +0000 (18:59 -0700)
sudoers and then just set the parsed value in update_defaults().

plugins/sudoers/defaults.c
plugins/sudoers/defaults.h
plugins/sudoers/gram.c
plugins/sudoers/gram.y
plugins/sudoers/ldap.c
plugins/sudoers/parse.h
plugins/sudoers/regress/parser/check_fill.c
plugins/sudoers/sssd.c

index bba1f6d51ef111415506218a1b3193767fe5bac2..5c8668d6cc1fd16fc08a4e718f93647f4a0b4c51 100644 (file)
@@ -79,21 +79,17 @@ static struct strmap priorities[] = {
 
 static struct early_default early_defaults[] = {
 #ifdef FQDN
-    { "fqdn", &sudo_defs_table[I_FQDN] },
+    { I_FQDN, true },
 #else
-    { "fqdn" },
+    { I_FQDN },
 #endif
-    { "match_group_by_gid" },
-    { "group_plugin" },
-    { "runas_default" },
-    { "sudoers_locale" },
-    { NULL }
+    { I_MATCH_GROUP_BY_GID },
+    { I_GROUP_PLUGIN },
+    { I_RUNAS_DEFAULT },
+    { I_SUDOERS_LOCALE },
+    { -1 }
 };
 
-/* Flags for set_default_entry() and set_default_int() */
-#define        FLAG_DO_CALLBACK        0x01
-#define        FLAG_QUIET              0x02
-
 /*
  * Local prototypes.
  */
@@ -196,16 +192,16 @@ dump_defaults(void)
 }
 
 static bool
-set_default_entry(struct sudo_defs_types *def, const char *val, int op,
-    const char *file, int lineno, int flags)
+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)
 {
     int rc;
-    debug_decl(set_default_entry, SUDOERS_DEBUG_DEFAULTS)
+    debug_decl(parse_default_entry, SUDOERS_DEBUG_DEFAULTS)
 
     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 (!ISSET(flags, FLAG_QUIET)) {
+           if (!quiet) {
                if (lineno > 0) {
                    sudo_warnx(U_("%s:%d no value specified for \"%s\""),
                        file, lineno, def->name);
@@ -220,14 +216,14 @@ set_default_entry(struct sudo_defs_types *def, const char *val, int op,
 
     switch (def->type & T_MASK) {
        case T_LOGFAC:
-           rc = store_syslogfac(val, &def->sd_un);
+           rc = store_syslogfac(val, sd_un);
            break;
        case T_LOGPRI:
-           rc = store_syslogpri(val, &def->sd_un);
+           rc = store_syslogpri(val, sd_un);
            break;
        case T_STR:
            if (ISSET(def->type, T_PATH) && val != NULL && *val != '/') {
-               if (!ISSET(flags, FLAG_QUIET)) {
+               if (!quiet) {
                    if (lineno > 0) {
                        sudo_warnx(U_("%s:%d values for \"%s\" must start with a '/'"),
                            file, lineno, def->name);
@@ -239,23 +235,23 @@ set_default_entry(struct sudo_defs_types *def, const char *val, int op,
                rc = -1;
                break;
            }
-           rc =  store_str(val, &def->sd_un);
+           rc =  store_str(val, sd_un);
            break;
        case T_INT:
-           rc = store_int(val, &def->sd_un);
+           rc = store_int(val, sd_un);
            break;
        case T_UINT:
-           rc = store_uint(val, &def->sd_un);
+           rc = store_uint(val, sd_un);
            break;
        case T_FLOAT:
-           rc = store_float(val, &def->sd_un);
+           rc = store_float(val, sd_un);
            break;
        case T_MODE:
-           rc = store_mode(val, &def->sd_un);
+           rc = store_mode(val, sd_un);
            break;
        case T_FLAG:
            if (val != NULL) {
-               if (!ISSET(flags, FLAG_QUIET)) {
+               if (!quiet) {
                    if (lineno > 0) {
                        sudo_warnx(U_("%s:%d option \"%s\" does not take a value"),
                            file, lineno, def->name);
@@ -267,17 +263,17 @@ set_default_entry(struct sudo_defs_types *def, const char *val, int op,
                rc = -1;
                break;
            }
-           def->sd_un.flag = op;
+           sd_un->flag = op;
            rc = true;
            break;
        case T_LIST:
-           rc = store_list(val, &def->sd_un, op);
+           rc = store_list(val, sd_un, op);
            break;
        case T_TUPLE:
-           rc = store_tuple(val, &def->sd_un, def->values);
+           rc = store_tuple(val, sd_un, def->values);
            break;
        default:
-           if (!ISSET(flags, FLAG_QUIET)) {
+           if (!quiet) {
                if (lineno > 0) {
                    sudo_warnx(U_("%s:%d invalid Defaults type 0x%x for option \"%s\""),
                        file, lineno, def->type, def->name);
@@ -289,13 +285,8 @@ set_default_entry(struct sudo_defs_types *def, const char *val, int op,
            rc = -1;
            break;
     }
-    switch (rc) {
-    case -1:
-       /* Error message already displayed. */
-       rc = false;
-       break;
-    case false:
-       if (!ISSET(flags, FLAG_QUIET)) {
+    if (rc == false) {
+       if (!quiet) {
            if (lineno > 0) {
                sudo_warnx(U_("%s:%d value \"%s\" is invalid for option \"%s\""),
                    file, lineno, val, def->name);
@@ -304,103 +295,93 @@ set_default_entry(struct sudo_defs_types *def, const char *val, int op,
                    file, val, def->name);
            }
        }
-       break;
-    case true:
-       if (ISSET(flags, FLAG_DO_CALLBACK) && def->callback)
-           rc = def->callback(&def->sd_un);
-       break;
     }
 
-    debug_return_bool(rc);
+    debug_return_bool(rc == true);
 }
 
 struct early_default *
-is_early_default(const char *var)
+is_early_default(int idx)
 {
     struct early_default *early;
     debug_decl(is_early_default, SUDOERS_DEBUG_DEFAULTS)
 
-    for (early = early_defaults; early->var != NULL; early++) {
-       if (strcmp(var, early->var) == 0)
+    for (early = early_defaults; early->idx != -1; early++) {
+       if (idx == early->idx)
            debug_return_ptr(early);
     }
     debug_return_ptr(NULL);
 }
 
-/*
- * Sets/clears an entry in the defaults structure.
- * If a variable that takes a value is used in a boolean
- * context with op == 0, disable that variable.
- * Eg. you may want to turn off logging to a file for some hosts.
- * 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, const char *file,
-    int lineno, int flags)
+struct early_default *
+is_early_default_byname(const char *name)
 {
-    struct sudo_defs_types *cur;
-    int num;
-    debug_decl(set_default_int, SUDOERS_DEBUG_DEFAULTS)
+    struct early_default *early;
+    debug_decl(is_early_default_byname, SUDOERS_DEBUG_DEFAULTS)
 
-    for (cur = sudo_defs_table, num = 0; cur->name; cur++, num++) {
-       if (strcmp(var, cur->name) == 0)
-           break;
-    }
-    if (!cur->name) {
-       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);
+    for (early = early_defaults; early->idx != -1; early++) {
+       if (strcmp(name, sudo_defs_table[early->idx].name) == 0)
+           debug_return_ptr(early);
     }
+    debug_return_ptr(NULL);
+}
+
+static bool
+run_callback(struct sudo_defs_types *def)
+{
+    debug_decl(run_callback, SUDOERS_DEBUG_DEFAULTS)
 
-    if (!set_default_entry(cur, val, op, file, lineno, flags))
-       debug_return_ptr(NULL);
-    debug_return_ptr(cur);
+    if (def->callback == NULL)
+       debug_return_bool(true);
+    debug_return_bool(def->callback(&def->sd_un));
 }
 
 /*
  * 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)
 {
-    const struct sudo_defs_types *def;
-    int flags = FLAG_DO_CALLBACK;
+    union sudo_defs_val sd_un;
+    int idx;
     debug_decl(set_default, SUDOERS_DEBUG_DEFAULTS)
 
-    if (quiet)
-       SET(flags, FLAG_QUIET);
-    def = set_default_int(var, val, op, file, lineno, flags);
-    debug_return_bool(def != NULL);
+    idx = parse_default(var, val, op, &sd_un, 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));
+    }
+    debug_return_bool(false);
 }
 
 /*
  * 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)
 {
-    const struct sudo_defs_types *def;
-    int flags = 0;
+    union sudo_defs_val sd_un;
+    int idx;
     debug_decl(set_early_default, SUDOERS_DEBUG_DEFAULTS)
 
-    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;
-    debug_return_bool(true);
+    idx = parse_default(var, val, op, &sd_un, file, lineno, quiet);
+    if (idx != -1) {
+       /* Set parsed value in sudo_defs_table. */
+       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);
+    }
+    debug_return_bool(false);
 }
 
 /*
@@ -413,14 +394,12 @@ run_early_defaults(void)
     bool ret = true;
     debug_decl(run_early_defaults, SUDOERS_DEBUG_DEFAULTS)
 
-    for (early = early_defaults; early->var != NULL; early++) {
-       if (early->def == NULL)
-           continue;
-       if (early->def->callback != NULL) {
-           if (!early->def->callback(&early->def->sd_un))
+    for (early = early_defaults; early->idx != -1; early++) {
+       if (early->run_callback) {
+           if (!run_callback(&sudo_defs_table[early->idx]))
                ret = false;
+           early->run_callback = false;
        }
-       early->def = NULL;
     }
     debug_return_bool(ret);
 }
@@ -711,16 +690,20 @@ 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->var);
+       struct early_default *early = is_early_default(d->idx);
        if (early == NULL)
            continue;
 
+       /* Defaults type and binding must match. */
        if (!default_type_matches(d, what) ||
            !default_binding_matches(d, what))
            continue;
-       if (!set_early_default(d->var, d->val, d->op, "sudoers", 0, quiet, early))
-           ret = false;
+
+       /* 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;
     }
+    /* Run callbacks for early defaults (if any) */
     if (!run_early_defaults())
        ret = false;
 
@@ -729,56 +712,51 @@ 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->var))
+       if (is_early_default(d->idx))
            continue;
 
+       /* Defaults type and binding must match. */
        if (!default_type_matches(d, what) ||
            !default_binding_matches(d, what))
            continue;
-       if (!set_default(d->var, d->val, d->op, "sudoers", 0, quiet))
+
+       /* 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]))
            ret = false;
     }
     debug_return_bool(ret);
 }
 
 /*
- * Check a defaults entry without actually setting it.
+ * Parse a defaults entry, storing the parsed entry in sd_un.
+ * Returns the matching sudo_defs_table[] index on success or -1 on failure.
  */
-bool
-check_default(const char *var, const char *val, int op, const char *file,
-    int lineno, 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)
 {
-    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(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, val, op, file, lineno, flags))
-               ret = false;
-           free_default(&tmp);
-           break;
+    int i;
+    debug_decl(parse_default, 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 (cur->name == NULL) {
-       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);
-           }
+    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);
+    debug_return_int(-1);
 }
 
 static bool
index 284d39c23592ccdab557d818249f53cd4e993feb..1b0d1db8599993f811f318d61d39a481bd6c1859 100644 (file)
@@ -70,8 +70,8 @@ struct sudo_defs_types {
  * Defaults values to apply before others.
  */
 struct early_default {
-    const char *var;
-    const struct sudo_defs_types *def;
+    short idx;
+    short run_callback;
 };
 
 /*
@@ -120,13 +120,14 @@ struct early_default {
  * Prototypes
  */
 void dump_default(void);
-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);
+struct early_default *is_early_default(int idx);
+struct early_default *is_early_default_byname(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);
 
 extern struct sudo_defs_types sudo_defs_table[];
 
index a87abdedfc894d28c4417ddf5748acb36879268e..917fd495c399c8a874c7999bb7267245f741c172 100644 (file)
@@ -826,7 +826,9 @@ 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->var, d->val, d->op, sudoers, sudolineno, !sudoers_warnings)) {
+           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;
@@ -834,14 +836,13 @@ add_defaults(int type, struct member *bmem, struct defaults *defs)
                TAILQ_INSERT_TAIL(&defaults, d, entries);
            } else {
                /* Did not parse */
-               if (!allow_unknown_defaults) {
+               if (ret && !allow_unknown_defaults) {
                    sudoerserror(NULL);
                    ret = false;
                }
                free(d->var);
                free(d->val);
                free(d);
-               continue;
            }
        }
 
@@ -995,6 +996,7 @@ init_parser(const char *path, bool quiet, bool strict_defaults)
            free_members(d->binding);
            free(d->binding);
        }
+       /* no need to free sd_un */
        free(d->var);
        free(d->val);
        free(d);
@@ -1027,7 +1029,7 @@ init_parser(const char *path, bool quiet, bool strict_defaults)
 
     debug_return_bool(ret);
 }
-#line 978 "gram.c"
+#line 980 "gram.c"
 /* allocate initial stack or double stack size, up to YYMAXDEPTH */
 #if defined(__cplusplus) || defined(__STDC__)
 static int yygrowstack(void)
@@ -2110,7 +2112,7 @@ case 115:
                            }
                        }
 break;
-#line 2061 "gram.c"
+#line 2063 "gram.c"
     }
     yyssp -= yym;
     yystate = *yyssp;
index 8f5e57d118df0ddcd761e9f10d9ababb81ce785a..145b9f5277e0bcfa75b65a71e67be280ffe70ccc 100644 (file)
@@ -982,7 +982,9 @@ 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->var, d->val, d->op, sudoers, sudolineno, !sudoers_warnings)) {
+           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;
@@ -990,14 +992,13 @@ add_defaults(int type, struct member *bmem, struct defaults *defs)
                TAILQ_INSERT_TAIL(&defaults, d, entries);
            } else {
                /* Did not parse */
-               if (!allow_unknown_defaults) {
+               if (ret && !allow_unknown_defaults) {
                    sudoerserror(NULL);
                    ret = false;
                }
                free(d->var);
                free(d->val);
                free(d);
-               continue;
            }
        }
 
@@ -1151,6 +1152,7 @@ init_parser(const char *path, bool quiet, bool strict_defaults)
            free_members(d->binding);
            free(d->binding);
        }
+       /* no need to free sd_un */
        free(d->var);
        free(d->val);
        free(d);
index 9aa586be4b291ade5100c04cf6e981984dc927eb..ef2074f458d016da927844c579b37a52696fa45c 100644 (file)
@@ -1158,7 +1158,7 @@ sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry)
            goto done;
        }
        op = sudo_ldap_parse_option(copy, &var, &val);
-       early = is_early_default(var);
+       early = is_early_default_byname(var);
        if (early != NULL) {
            set_early_default(var, val, op,
                source ? source : "sudoRole UNKNOWN", 0, false, early);
@@ -1174,7 +1174,7 @@ sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry)
            goto done;
        }
        op = sudo_ldap_parse_option(copy, &var, &val);
-       if (is_early_default(var) == NULL) {
+       if (is_early_default_byname(var) == NULL) {
            set_default(var, val, op,
                source ? source : "sudoRole UNKNOWN", 0, false);
        }
index bdb28e0b6deac39cf3a02c84c705d36e64c583ca..74eeb4c7f77b54e06ff25cef84b242db610f55f8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 1998-2000, 2004, 2007-2015
+ * Copyright (c) 1996, 1998-2000, 2004, 2007-2016
  *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -214,7 +214,7 @@ struct alias {
 };
 
 /*
- * Structure describing a Defaults entry and a list thereof.
+ * Structure describing a Defaults entry in sudoers.
  */
 struct defaults {
     TAILQ_ENTRY(defaults) entries;
@@ -223,6 +223,8 @@ struct defaults {
     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 */
 };
 
 /*
index 95fdcae2a57f6afff7efa05f8759d2bcaf17c6ac..65363d98c0e0146a213a01185f9cfb7289b40099 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2013 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2011-2016 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -37,6 +37,7 @@
 
 #include "sudo_compat.h"
 #include "sudo_queue.h"
+#include "defaults.h"
 #include "parse.h"
 #include "toke.h"
 #include "sudo_plugin.h"
index c1bf7baf32ca206c643af42e9fe338e3aa6ecc51..8ef4c9d41cb232fe5cf57b34fc9040780ed68b8f 100644 (file)
@@ -1239,7 +1239,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(var);
+       early = is_early_default_byname(var);
        if (early != NULL) {
            set_early_default(var, val, op,
                source ? source : "sudoRole UNKNOWN", 0, false, early);
@@ -1255,7 +1255,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(var) == NULL) {
+       if (is_early_default_byname(var) == NULL) {
            set_default(var, val, op,
                source ? source : "sudoRole UNKNOWN", 0, false);
        }