#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)