diff options
Diffstat (limited to 'libselinux/src/context.c')
-rw-r--r-- | libselinux/src/context.c | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/libselinux/src/context.c b/libselinux/src/context.c new file mode 100644 index 00000000..81641041 --- /dev/null +++ b/libselinux/src/context.c @@ -0,0 +1,193 @@ +#include "context_internal.h" +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#define COMP_USER 0 +#define COMP_ROLE 1 +#define COMP_TYPE 2 +#define COMP_RANGE 3 + +typedef struct { + char *current_str; /* This is made up-to-date only when needed */ + char *(component[4]); +} context_private_t; + +/* + * Allocate a new context, initialized from str. There must be 3 or + * 4 colon-separated components and no whitespace in any component other + * than the MLS component. + */ +context_t context_new(const char *str) +{ + int i, count; + context_private_t *n = + (context_private_t *) malloc(sizeof(context_private_t)); + context_t result = (context_t) malloc(sizeof(context_s_t)); + const char *p, *tok; + + if (result) + result->ptr = n; + else + free(n); + if (n == 0 || result == 0) { + goto err; + } + n->current_str = n->component[0] = n->component[1] = n->component[2] = + n->component[3] = 0; + for (i = count = 0, p = str; *p; p++) { + switch (*p) { + case ':': + count++; + break; + case '\n': + case '\t': + case '\r': + goto err; /* sanity check */ + case ' ': + if (count < 3) + goto err; /* sanity check */ + } + } + /* + * Could be anywhere from 2 - 5 + * e.g user:role:type to user:role:type:sens1:cata-sens2:catb + */ + if (count < 2 || count > 5) { /* might not have a range */ + goto err; + } + + n->component[3] = 0; + for (i = 0, tok = str; *tok; i++) { + if (i < 3) + for (p = tok; *p && *p != ':'; p++) { /* empty */ + } else { + /* MLS range is one component */ + for (p = tok; *p; p++) { /* empty */ + } + } + n->component[i] = (char *)malloc(p - tok + 1); + if (n->component[i] == 0) + goto err; + strncpy(n->component[i], tok, p - tok); + n->component[i][p - tok] = '\0'; + tok = *p ? p + 1 : p; + } + return result; + err: + context_free(result); + return 0; +} + +hidden_def(context_new) + +static void conditional_free(char **v) +{ + if (*v) { + free(*v); + } + *v = 0; +} + +/* + * free all storage used by a context. Safe to call with + * null pointer. + */ +void context_free(context_t context) +{ + context_private_t *n; + int i; + if (context) { + n = context->ptr; + if (n) { + conditional_free(&n->current_str); + for (i = 0; i < 4; i++) { + conditional_free(&n->component[i]); + } + free(n); + } + free(context); + } +} + +hidden_def(context_free) + +/* + * Return a pointer to the string value of the context. + */ +char *context_str(context_t context) +{ + context_private_t *n = context->ptr; + int i; + size_t total = 0; + conditional_free(&n->current_str); + for (i = 0; i < 4; i++) { + if (n->component[i]) { + total += strlen(n->component[i]) + 1; + } + } + n->current_str = malloc(total); + if (n->current_str != 0) { + char *cp = n->current_str; + + cp = stpcpy(cp, n->component[0]); + for (i = 1; i < 4; i++) { + if (n->component[i]) { + *cp++ = ':'; + cp = stpcpy(cp, n->component[i]); + } + } + } + return n->current_str; +} + +hidden_def(context_str) + +/* Returns nonzero iff failed */ +static int set_comp(context_private_t * n, int idx, const char *str) +{ + char *t = NULL; + const char *p; + if (str) { + t = (char *)malloc(strlen(str) + 1); + if (!t) { + return 1; + } + for (p = str; *p; p++) { + if (*p == '\t' || *p == '\n' || *p == '\r' || + ((*p == ':' || *p == ' ') && idx != COMP_RANGE)) { + free(t); + errno = EINVAL; + return 1; + } + } + strcpy(t, str); + } + conditional_free(&n->component[idx]); + n->component[idx] = t; + return 0; +} + +#define def_get(name,tag) \ +const char * context_ ## name ## _get(context_t context) \ +{ \ + context_private_t *n = context->ptr; \ + return n->component[tag]; \ +} \ +hidden_def(context_ ## name ## _get) + +def_get(type, COMP_TYPE) + def_get(user, COMP_USER) + def_get(range, COMP_RANGE) + def_get(role, COMP_ROLE) +#define def_set(name,tag) \ +int context_ ## name ## _set(context_t context, const char* str) \ +{ \ + return set_comp(context->ptr,tag,str);\ +} \ +hidden_def(context_ ## name ## _set) + def_set(type, COMP_TYPE) + def_set(role, COMP_ROLE) + def_set(user, COMP_USER) + def_set(range, COMP_RANGE) |