Blob Blame History Raw
#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)