#include <stdio.h>
#include "mls_level.h"
#include <sepol/policydb/ebitmap.h>
mls_level_t *mls_level_from_string(char *mls_context)
{
char delim;
char *scontextp, *p, *lptr;
mls_level_t *l;
if (!mls_context) {
return NULL;
}
l = (mls_level_t *) calloc(1, sizeof(mls_level_t));
/* Extract low sensitivity. */
scontextp = p = mls_context;
while (*p && *p != ':' && *p != '-')
p++;
delim = *p;
if (delim != 0)
*p++ = 0;
if (*scontextp != 's')
goto err;
l->sens = atoi(scontextp + 1);
if (delim == ':') {
/* Extract category set. */
while (1) {
scontextp = p;
while (*p && *p != ',' && *p != '-')
p++;
delim = *p;
if (delim != 0)
*p++ = 0;
/* Separate into level if exists */
if ((lptr = strchr(scontextp, '.')) != NULL) {
/* Remove '.' */
*lptr++ = 0;
}
if (*scontextp != 'c')
goto err;
int bit = atoi(scontextp + 1);
if (ebitmap_set_bit(&l->cat, bit, 1))
goto err;
/* If level, set all categories in level */
if (lptr) {
if (*lptr != 'c')
goto err;
int ubit = atoi(lptr + 1);
int i;
for (i = bit + 1; i <= ubit; i++) {
if (ebitmap_set_bit
(&l->cat, i, 1))
goto err;
}
}
if (delim != ',')
break;
}
}
return l;
err:
free(l);
return NULL;
}
/*
* Return the length in bytes for the MLS fields of the
* security context string representation of `context'.
*/
unsigned int mls_compute_string_len(mls_level_t *l)
{
unsigned int len = 0;
char temp[16];
unsigned int i, level = 0;
ebitmap_node_t *cnode;
if (!l)
return 0;
len += snprintf(temp, sizeof(temp), "s%d", l->sens);
ebitmap_for_each_bit(&l->cat, cnode, i) {
if (ebitmap_node_get_bit(cnode, i)) {
if (level) {
level++;
continue;
}
len++; /* : or ,` */
len += snprintf(temp, sizeof(temp), "c%d", i);
level++;
} else {
if (level > 1)
len += snprintf(temp, sizeof(temp), ".c%d", i-1);
level = 0;
}
}
/* Handle case where last category is the end of level */
if (level > 1)
len += snprintf(temp, sizeof(temp), ".c%d", i-1);
return len;
}
char *mls_level_to_string(mls_level_t *l)
{
unsigned int wrote_sep, len = mls_compute_string_len(l);
unsigned int i, level = 0;
ebitmap_node_t *cnode;
wrote_sep = 0;
if (len == 0)
return NULL;
char *result = (char *)malloc(len + 1);
char *p = result;
p += sprintf(p, "s%d", l->sens);
/* categories */
ebitmap_for_each_bit(&l->cat, cnode, i) {
if (ebitmap_node_get_bit(cnode, i)) {
if (level) {
level++;
continue;
}
if (!wrote_sep) {
*p++ = ':';
wrote_sep = 1;
} else
*p++ = ',';
p += sprintf(p, "c%d", i);
level++;
} else {
if (level > 1) {
if (level > 2)
*p++ = '.';
else
*p++ = ',';
p += sprintf(p, "c%d", i-1);
}
level = 0;
}
}
/* Handle case where last category is the end of level */
if (level > 1) {
if (level > 2)
*p++ = '.';
else
*p++ = ',';
p += sprintf(p, "c%d", i-1);
}
*(result + len) = 0;
return result;
}