| #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; |
| errno = 0; |
| 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: |
| if (errno == 0) errno = EINVAL; |
| 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; |
| |
| strcpy(cp, n->component[0]); |
| cp += strlen(cp); |
| for (i = 1; i < 4; i++) { |
| if (n->component[i]) { |
| *cp++ = ':'; |
| strcpy(cp, n->component[i]); |
| cp += strlen(cp); |
| } |
| } |
| } |
| 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) |