
Add support for read-only and write-once.
Signed-off-by: Joe Hershberger joe.hershberger@ni.com --- README | 13 +++++++++++- common/cmd_nvedit.c | 51 ++++++++++++++++++++++++++++++++++++++++++++ common/env_acl.c | 38 +++++++++++++++++++++++++++++++++ include/env_acl.h | 14 ++++++++++++ tools/env/fw_env.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 176 insertions(+), 1 deletion(-)
diff --git a/README b/README index 2e34bcd..fa665f0 100644 --- a/README +++ b/README @@ -2094,6 +2094,11 @@ The following options need to be configured: serial# is unaffected by this, i. e. it remains read-only.]
+ The same can be accomplished in a more flexible way + for any variable by defining CONFIG_ENV_ACL and + specifying the type of access to allow to each + variable. + - Protected RAM: CONFIG_PRAM
@@ -2916,7 +2921,8 @@ Configuration Settings:
The format of the list is: type_attribute = [s|d|x|b|i|m] - attributes = type_attribute + access_atribute = [a|r|o] + attributes = type_attribute[access_atribute] entry = variable_name[:attributes] list = entry[,list]
@@ -2928,6 +2934,11 @@ Configuration Settings: i - IP address m - MAC address
+ The access attributes are: + a - Any (default) + r - Read-only + o - Write-once (change default) + - CONFIG_ENV_ACL_DEFAULT Define this to a list (string) to define the "acl" envirnoment variable in the default or embedded environment. diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index b761b2c..13b6e08 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -200,6 +200,23 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag, } #endif
+#ifdef CONFIG_ENV_ACL +/* + * Look up the variable from the default environment + */ +static char *getdefenv(const char *name) +{ + char *ret_val; + unsigned long really_valid = gd->env_valid; + + /* Pretend that the image is bad. */ + gd->env_valid = 0; + ret_val = getenv(name); + gd->env_valid = really_valid; + return ret_val; +} +#endif + /* * Set a new environment variable, * or replace or delete an existing one. @@ -237,6 +254,40 @@ int _do_env_set(int flag, int argc, char * const argv[]) creating = (!ep && ((argc >= 3) && argv[2] != NULL)); overwriting = (ep && ((argc >= 3) && argv[2] != NULL));
+#ifdef CONFIG_ENV_ACL + /* check for permission */ + if (deleting) { + if (env_acl_validate_access(name, ENV_ACL_PREVENT_DELETE)) { + printf("## Error: Can't delete "%s"\n", name); + return 1; + } + } else if (overwriting) { + if (env_acl_validate_access(name, ENV_ACL_PREVENT_OVERWR)) { + printf("## Error: Can't overwrite "%s"\n", name); + return 1; + } else if (env_acl_validate_access(name, + ENV_ACL_PREVENT_NONDEF_OVERWR)) { + const char *defval = getdefenv(name); + + if (defval == NULL) + defval = ""; + if (strcmp(ep->data, defval) + != 0) { + printf("## Error: Can't overwrite "%s"\n", + name); + return 1; + } + } + } else if (creating) { + if (env_acl_validate_access(name, ENV_ACL_PREVENT_CREATE)) { + printf("## Error: Can't create "%s"\n", name); + return 1; + } + } else + /* Nothing to do */ + return 0; +#endif + /* Check for console redirection */ if (strcmp(name, "stdin") == 0) console = stdin; diff --git a/common/env_acl.c b/common/env_acl.c index 7c86243..1a75e09 100644 --- a/common/env_acl.c +++ b/common/env_acl.c @@ -47,6 +47,12 @@
static const char env_acl_static[] = CONFIG_ENV_ACL_STATIC "\0"; static const char env_acl_type_rep[] = "sdxb" ENV_ACL_NET_TYPE_REPS; +static const char env_acl_access_rep[] = "aro"; +static const char env_acl_access_mask[] = { + 0, + ENV_ACL_PREVENT_DELETE | ENV_ACL_PREVENT_CREATE | + ENV_ACL_PREVENT_OVERWR, + ENV_ACL_PREVENT_DELETE | ENV_ACL_PREVENT_NONDEF_OVERWR};
static int _env_acl_lookup_r(const char *name, char *attributes, int static_acl) { @@ -147,6 +153,27 @@ enum env_acl_var_type env_acl_get_type(const char *name) return ENV_ACL_VAR_TYPE_STRING; }
+enum env_acl_var_access env_acl_get_access(const char *name) +{ + char *access; + char attr[ENV_ACL_ATTR_MAX_LEN + 1]; + if (env_acl_lookup_r(name, attr)) + return ENV_ACL_VAR_ACCESS_ANY; + + if (strlen(attr) <= ENV_ACL_ACCESS_LOC) + return ENV_ACL_VAR_ACCESS_ANY; + + access = strchr(env_acl_access_rep, attr[ENV_ACL_ACCESS_LOC]); + + if (access != NULL) + return (enum env_acl_var_access) + (access - &env_acl_access_rep[0]); + + printf("## Warning: Unknown environment variable access method '%c'\n", + attr[ENV_ACL_ACCESS_LOC]); + return ENV_ACL_VAR_ACCESS_ANY; +} + static inline int is_hex_prefix(const char *value) { return value[0] == '0' && (value[1] == 'x' || value[1] == 'X'); @@ -249,6 +276,17 @@ int env_acl_validate_type(const char *name, const char *value) return 0; }
+int env_acl_validate_access(const char *name, int check_mask) +{ + enum env_acl_var_access access; + int access_mask; + + access = env_acl_get_access(name); + access_mask = env_acl_access_mask[access]; + + return (check_mask & access_mask) != 0; +} + int env_acl_validate_env_set_params(int argc, char * const argv[]) { if ((argc >= 3) && argv[2] != NULL) { diff --git a/include/env_acl.h b/include/env_acl.h index 9b0a199..09618f9 100644 --- a/include/env_acl.h +++ b/include/env_acl.h @@ -35,14 +35,28 @@ enum env_acl_var_type { #endif };
+enum env_acl_var_access { + ENV_ACL_VAR_ACCESS_ANY, + ENV_ACL_VAR_ACCESS_READ, + ENV_ACL_VAR_ACCESS_SET_ONCE, +}; + +#define ENV_ACL_PREVENT_DELETE 0x01 +#define ENV_ACL_PREVENT_CREATE 0x02 +#define ENV_ACL_PREVENT_OVERWR 0x04 +#define ENV_ACL_PREVENT_NONDEF_OVERWR 0x08 + #define ENV_ACL_LIST_DELIM ',' #define ENV_ACL_ATTR_SEP ':' #define ENV_ACL_LIST_VAR_NAME "acl" #define ENV_ACL_ATTR_MAX_LEN 2 #define ENV_ACL_TYPE_LOC 0 +#define ENV_ACL_ACCESS_LOC 1
enum env_acl_var_type env_acl_get_type(const char *name); +enum env_acl_var_access env_acl_get_access(const char *name); int env_acl_validate_type(const char *name, const char *value); +int env_acl_validate_access(const char *name, int check_mask); int env_acl_validate_env_set_params(int argc, char * const argv[]);
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c index f7807b5..60ff06c 100644 --- a/tools/env/fw_env.c +++ b/tools/env/fw_env.c @@ -268,6 +268,34 @@ char *fw_getenv (char *name) return NULL; }
+#ifdef CONFIG_ENV_ACL +/* + * Search the default environment for a variable. + * Return the value, if found, or NULL, if not found. + */ +char *fw_getdefenv(char *name) +{ + char *env, *nxt; + + for (env = default_environment; *env; env = nxt + 1) { + char *val; + + for (nxt = env; *nxt; ++nxt) { + if (nxt >= &default_environment[ENV_SIZE]) { + fprintf(stderr, "## Error: " + "default environment not terminated\n"); + return NULL; + } + } + val = envmatch(name, env); + if (!val) + continue; + return val; + } + return NULL; +} +#endif + /* * Print the current definition of one, or more, or all * environment variables @@ -391,6 +419,39 @@ int fw_env_write(char *name, char *value) creating = (!oldval && (value && strlen(value))); overwriting = (oldval && (value && strlen(value)));
+#ifdef CONFIG_ENV_ACL + /* check for permission */ + if (deleting) { + if (env_acl_validate_access(name, ENV_ACL_PREVENT_DELETE)) { + printf("Can't delete "%s"\n", name); + return 1; + } + } else if (overwriting) { + if (env_acl_validate_access(name, ENV_ACL_PREVENT_OVERWR)) { + printf("Can't overwrite "%s"\n", name); + return 1; + } else if (env_acl_validate_access(name, + ENV_ACL_PREVENT_NONDEF_OVERWR)) { + const char *defval = fw_getdefenv(name); + + if (defval == NULL) + defval = ""; + if (strcmp(oldval, defval) + != 0) { + printf("Can't overwrite "%s"\n", name); + return 1; + } + } + } else if (creating) { + if (env_acl_validate_access(name, ENV_ACL_PREVENT_CREATE)) { + printf("Can't create "%s"\n", name); + return 1; + } + } else + /* Nothing to do */ + return 0; +#endif + if (deleting || overwriting) { #ifndef CONFIG_ENV_OVERWRITE /*