2008-08-19 19:30:36 +00:00
|
|
|
#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;
|
2010-03-24 13:17:03 +00:00
|
|
|
errno = 0;
|
2008-08-19 19:30:36 +00:00
|
|
|
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:
|
2010-03-24 13:17:03 +00:00
|
|
|
if (errno == 0) errno = EINVAL;
|
2008-08-19 19:30:36 +00:00
|
|
|
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)
|