| #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; |
| } |