blob: 3f97268dc4dd48f6e6ccb6d2451db52ee8e88566 [file] [log] [blame]
/*
* version_policy.c - Takes the given public platform policy, a private policy
* and a version number to produced a combined "versioned" policy file.
*/
#include <errno.h>
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/stat.h>
#include <cil/android.h>
#include <cil/cil.h>
void __attribute__ ((noreturn)) static usage(char *prog) {
printf("Usage: %s [OPTION]...\n", prog);
printf("\n");
printf("Options:\n");
printf(" -b, --base=<file> (req'd) base policy for versioning.\n");
printf(" -m, --mapping generate cil version mapping from base policy\n");
printf(" -n, --number (req'd) version number to use.\n");
printf(" -o, --output=<file> write cil policy to <file>\n");
printf(" -t, --tgt_policy policy to be versioned according to base policy\n");
printf(" -h, --help display usage information\n");
exit(1);
}
/*
* read_cil_file - Initialize db and parse CIL input file.
*/
static int read_cil_file(struct cil_db **db, char *path) {
int rc = SEPOL_ERR;
FILE *file;
struct stat filedata;
uint32_t file_size;
char *buff = NULL;
cil_db_init(db);
file = fopen(path, "re");
if (!file) {
fprintf(stderr, "Could not open file: %s\n", path);
goto file_err;
}
rc = stat(path, &filedata);
if (rc == -1) {
fprintf(stderr, "Could not stat file: %s - %s\n", path, strerror(errno));
goto err;
}
file_size = filedata.st_size;
buff = malloc(file_size);
if (buff == NULL) {
fprintf(stderr, "OOM!\n");
rc = SEPOL_ERR;
goto err;
}
rc = fread(buff, file_size, 1, file);
if (rc != 1) {
fprintf(stderr, "Failure reading file: %s\n", path);
rc = SEPOL_ERR;
goto err;
}
fclose(file);
file = NULL;
/* creates parse_tree */
rc = cil_add_file(*db, path, buff, file_size);
if (rc != SEPOL_OK) {
fprintf(stderr, "Failure adding %s to parse tree\n", path);
goto parse_err;
}
free(buff);
return SEPOL_OK;
err:
fclose(file);
parse_err:
free(buff);
file_err:
cil_db_destroy(db);
return rc;
}
int main(int argc, char *argv[])
{
int opt_char;
int opt_index = 0;
int rc = SEPOL_ERR;
bool mapping = false;
char *base = NULL;
char *tgt_policy = NULL;
char *num = NULL;
char *dot;
char *output = NULL;
FILE *output_file = NULL;
struct cil_db *base_db = NULL;
struct cil_db *out_db = NULL;
static struct option long_opts[] = {
{"help", no_argument, 0, 'h'},
{"base", required_argument, 0, 'b'},
{"mapping", no_argument, 0, 'm'},
{"number", required_argument, 0, 'n'},
{"output", required_argument, 0, 'o'},
{"tgt_policy", required_argument, 0, 't'},
{0, 0, 0, 0}
};
while (1) {
opt_char = getopt_long(argc, argv, "b:mn:o:t:h", long_opts, &opt_index);
if (opt_char == -1) {
break;
}
switch (opt_char) {
case 'b':
base = strdup(optarg);
break;
case 'm':
mapping = true;
break;
case 'n':
num = strdup(optarg);
break;
case 'o':
output = strdup(optarg);
break;
case 't':
tgt_policy = strdup(optarg);
break;
case 'h':
usage(argv[0]);
default:
fprintf(stderr, "Unsupported option: %s\n", optarg);
usage(argv[0]);
}
}
if (optind < argc) {
fprintf(stderr, "Unknown arguments supplied\n");
usage(argv[0]);
}
if (num == NULL || base == NULL || (mapping == false && tgt_policy == NULL)) {
fprintf(stderr, "Please specify required arguments\n");
usage(argv[0]);
}
/* policy language doesn't like '.', so replace them with '_' in mapping version */
dot = num;
while ((dot = strchr(dot, '.')) != NULL) {
*dot = '_';
++dot;
}
if (mapping && tgt_policy) {
fprintf(stderr, "Please select only one mode between --mapping and --tgt_policy\n");
usage(argv[0]);
}
/* gimme only the important details */
cil_set_log_level(CIL_WARN);
/* read platform policy */
rc = read_cil_file(&base_db, base);
if (rc != SEPOL_OK) {
goto exit;
}
if (mapping) {
rc = cil_android_attrib_mapping(&out_db, base_db, num);
if (rc != SEPOL_OK)
goto exit;
} else {
/* read target policy, ready for manipulation */
rc = read_cil_file(&out_db, tgt_policy);
if (rc != SEPOL_OK) {
goto exit;
}
/* attributize the target policy */
rc = cil_android_attributize(out_db, base_db, num);
if (rc != SEPOL_OK) {
goto exit;
}
}
output_file = fopen(output, "we");
if (!output_file) {
fprintf(stderr, "Could not open file: %s\n", output);
goto exit;
}
rc = cil_write_build_ast(output_file, out_db);
if (rc != SEPOL_OK) {
fprintf(stderr, "Failed to write AST\n");
goto build_err;
}
build_err:
fclose(output_file);
exit:
free(base);
free(tgt_policy);
free(num);
free(output);
cil_db_destroy(&base_db);
cil_db_destroy(&out_db);
return rc;
}