@@ -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.
@@ -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;
@@ -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) {
@@ -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[]);
@@ -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
/*
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(-)