#include "context_internal.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.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 index, 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 == ' ') && index != COMP_RANGE) ) {
free(t);
return 1;
}
}
strcpy(t,str);
}
conditional_free(&n->component[index]);
n->component[index] = 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)