#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <sepol/policydb/policydb.h>
#include <sepol/policydb/conditional.h>
#include "debug.h"
#include "private.h"
#include "dso.h"
/* -- Deprecated -- */
static char *strtrim(char *dest, char *source, int size)
{
int i = 0;
char *ptr = source;
i = 0;
while (isspace(*ptr) && i < size) {
ptr++;
i++;
}
strncpy(dest, ptr, size);
for (i = strlen(dest) - 1; i > 0; i--) {
if (!isspace(dest[i]))
break;
}
dest[i + 1] = '\0';
return dest;
}
static int process_boolean(char *buffer, char *name, int namesize, int *val)
{
char name1[BUFSIZ];
char *ptr = NULL;
char *tok;
/* Skip spaces */
while (isspace(buffer[0]))
buffer++;
/* Ignore comments */
if (buffer[0] == '#')
return 0;
tok = strtok_r(buffer, "=", &ptr);
if (!tok) {
ERR(NULL, "illegal boolean definition %s", buffer);
return -1;
}
strncpy(name1, tok, BUFSIZ - 1);
strtrim(name, name1, namesize - 1);
tok = strtok_r(NULL, "\0", &ptr);
if (!tok) {
ERR(NULL, "illegal boolean definition %s=%s", name, buffer);
return -1;
}
while (isspace(*tok))
tok++;
*val = -1;
if (isdigit(tok[0]))
*val = atoi(tok);
else if (!strncasecmp(tok, "true", sizeof("true") - 1))
*val = 1;
else if (!strncasecmp(tok, "false", sizeof("false") - 1))
*val = 0;
if (*val != 0 && *val != 1) {
ERR(NULL, "illegal value for boolean %s=%s", name, tok);
return -1;
}
return 1;
}
static int load_booleans(struct policydb *policydb, const char *path,
int *changesp)
{
FILE *boolf;
char *buffer = NULL;
char localbools[BUFSIZ];
char name[BUFSIZ];
int val;
int errors = 0, changes = 0;
struct cond_bool_datum *datum;
boolf = fopen(path, "r");
if (boolf == NULL)
goto localbool;
#ifdef __APPLE__
if ((buffer = (char *)malloc(255 * sizeof(char))) == NULL) {
ERR(NULL, "out of memory");
return -1;
}
while(fgets(buffer, 255, boolf) != NULL) {
#else
size_t size = 0;
while (getline(&buffer, &size, boolf) > 0) {
#endif
int ret = process_boolean(buffer, name, sizeof(name), &val);
if (ret == -1)
errors++;
if (ret == 1) {
datum = hashtab_search(policydb->p_bools.table, name);
if (!datum) {
ERR(NULL, "unknown boolean %s", name);
errors++;
continue;
}
if (datum->state != val) {
datum->state = val;
changes++;
}
}
}
fclose(boolf);
localbool:
snprintf(localbools, sizeof(localbools), "%s.local", path);
boolf = fopen(localbools, "r");
if (boolf != NULL) {
#ifdef __APPLE__
while(fgets(buffer, 255, boolf) != NULL) {
#else
while (getline(&buffer, &size, boolf) > 0) {
#endif
int ret =
process_boolean(buffer, name, sizeof(name), &val);
if (ret == -1)
errors++;
if (ret == 1) {
datum =
hashtab_search(policydb->p_bools.table,
name);
if (!datum) {
ERR(NULL, "unknown boolean %s", name);
errors++;
continue;
}
if (datum->state != val) {
datum->state = val;
changes++;
}
}
}
fclose(boolf);
}
free(buffer);
if (errors)
errno = EINVAL;
*changesp = changes;
return errors ? -1 : 0;
}
int sepol_genbools(void *data, size_t len, const char *booleans)
{
struct policydb policydb;
struct policy_file pf;
int rc, changes = 0;
if (policydb_init(&policydb))
goto err;
if (policydb_from_image(NULL, data, len, &policydb) < 0)
goto err;
if (load_booleans(&policydb, booleans, &changes) < 0) {
WARN(NULL, "error while reading %s", booleans);
}
if (!changes)
goto out;
if (evaluate_conds(&policydb) < 0) {
ERR(NULL, "error while re-evaluating conditionals");
errno = EINVAL;
goto err_destroy;
}
policy_file_init(&pf);
pf.type = PF_USE_MEMORY;
pf.data = data;
pf.len = len;
rc = policydb_write(&policydb, &pf);
if (rc) {
ERR(NULL, "unable to write new binary policy image");
errno = EINVAL;
goto err_destroy;
}
out:
policydb_destroy(&policydb);
return 0;
err_destroy:
policydb_destroy(&policydb);
err:
return -1;
}
int hidden sepol_genbools_policydb(policydb_t * policydb, const char *booleans)
{
int rc, changes = 0;
rc = load_booleans(policydb, booleans, &changes);
if (!rc && changes)
rc = evaluate_conds(policydb);
if (rc)
errno = EINVAL;
return rc;
}
/* -- End Deprecated -- */
int sepol_genbools_array(void *data, size_t len, char **names, int *values,
int nel)
{
struct policydb policydb;
struct policy_file pf;
int rc, i, errors = 0;
struct cond_bool_datum *datum;
/* Create policy database from image */
if (policydb_init(&policydb))
goto err;
if (policydb_from_image(NULL, data, len, &policydb) < 0)
goto err;
for (i = 0; i < nel; i++) {
datum = hashtab_search(policydb.p_bools.table, names[i]);
if (!datum) {
ERR(NULL, "boolean %s no longer in policy", names[i]);
errors++;
continue;
}
if (values[i] != 0 && values[i] != 1) {
ERR(NULL, "illegal value %d for boolean %s",
values[i], names[i]);
errors++;
continue;
}
datum->state = values[i];
}
if (evaluate_conds(&policydb) < 0) {
ERR(NULL, "error while re-evaluating conditionals");
errno = EINVAL;
goto err_destroy;
}
policy_file_init(&pf);
pf.type = PF_USE_MEMORY;
pf.data = data;
pf.len = len;
rc = policydb_write(&policydb, &pf);
if (rc) {
ERR(NULL, "unable to write binary policy");
errno = EINVAL;
goto err_destroy;
}
if (errors) {
errno = EINVAL;
goto err_destroy;
}
policydb_destroy(&policydb);
return 0;
err_destroy:
policydb_destroy(&policydb);
err:
return -1;
}