summaryrefslogtreecommitdiffstats
path: root/sediff/sediff.c
diff options
context:
space:
mode:
Diffstat (limited to 'sediff/sediff.c')
-rw-r--r--sediff/sediff.c653
1 files changed, 653 insertions, 0 deletions
diff --git a/sediff/sediff.c b/sediff/sediff.c
new file mode 100644
index 0000000..6022775
--- /dev/null
+++ b/sediff/sediff.c
@@ -0,0 +1,653 @@
+/**
+ * @file
+ * Command line frontend for computing a semantic policy difference.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2006-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <poldiff/poldiff.h>
+#include <poldiff/component_record.h>
+#include <apol/policy.h>
+#include <apol/vector.h>
+#include <stdio.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define COPYRIGHT_INFO "Copyright (C) 2004-2007 Tresys Technology, LLC"
+
+enum opt_values
+{
+ DIFF_LEVEL = 256, DIFF_CATEGORY,
+ DIFF_AUDITALLOW, DIFF_DONTAUDIT, DIFF_NEVERALLOW,
+ DIFF_TYPE_CHANGE, DIFF_TYPE_MEMBER, DIFF_TYPE_TRANS,
+ DIFF_ROLE_TRANS, DIFF_ROLE_ALLOW, DIFF_RANGE_TRANS,
+ OPT_STATS
+};
+
+/* command line options struct */
+static struct option const longopts[] = {
+ {"class", no_argument, NULL, 'c'},
+ {"level", no_argument, NULL, DIFF_LEVEL},
+ {"category", no_argument, NULL, DIFF_CATEGORY},
+ {"type", no_argument, NULL, 't'},
+ {"attribute", no_argument, NULL, 'a'},
+ {"role", no_argument, NULL, 'r'},
+ {"user", no_argument, NULL, 'u'},
+ {"bool", no_argument, NULL, 'b'},
+ {"allow", no_argument, NULL, 'A'},
+ {"auditallow", no_argument, NULL, DIFF_AUDITALLOW},
+ {"dontaudit", no_argument, NULL, DIFF_DONTAUDIT},
+ {"neverallow", no_argument, NULL, DIFF_NEVERALLOW},
+ {"type_change", no_argument, NULL, DIFF_TYPE_CHANGE},
+ {"type_trans", no_argument, NULL, DIFF_TYPE_TRANS},
+ {"type_member", no_argument, NULL, DIFF_TYPE_MEMBER},
+ {"role_trans", no_argument, NULL, DIFF_ROLE_TRANS},
+ {"role_allow", no_argument, NULL, DIFF_ROLE_ALLOW},
+ {"range_trans", no_argument, NULL, DIFF_RANGE_TRANS},
+ {"stats", no_argument, NULL, OPT_STATS},
+ {"quiet", no_argument, NULL, 'q'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0}
+};
+
+static void usage(const char *prog_name, int brief)
+{
+ printf("Usage: %s [OPTIONS] ORIGINAL_POLICY ; MODIFIED_POLICY\n\n", prog_name);
+ if (brief) {
+ printf("\tTry %s --help for more help.\n\n", prog_name);
+ return;
+ }
+ printf("Semantically differentiate two policies. By default, all supported\n");
+ printf("policy elements sans neverallows are examined. The following options\n");
+ printf("are available:\n\n");
+ printf(" -c, --class object class and common permission definitions\n");
+ printf(" --level MLS level definitions\n");
+ printf(" --category MLS category definitions\n");
+ printf(" -t, --type type definitions\n");
+ printf(" -a, --attribute attribute definitions\n");
+ printf(" -r, --role role definitions\n");
+ printf(" -u, --user user definitions\n");
+ printf(" -b, --bool boolean definitions and default values\n");
+ printf(" -A, --allow allow rules\n");
+ printf(" --auditallow auditallow rules\n");
+ printf(" --dontaudit dontaudit rules\n");
+ printf(" --neverallow neverallow rules\n");
+ printf(" --type_change type_change rules\n");
+ printf(" --type_member type_member rules\n");
+ printf(" --type_trans type_transition rules\n");
+ printf(" --role_trans role_transition rules\n");
+ printf(" --role_allow role allow rules\n");
+ printf(" --range_trans range_transition rules\n");
+ printf("\n");
+ printf(" -q, --quiet suppress status output for elements with no differences\n");
+ printf(" --stats print only statistics\n");
+ printf(" -h, --help print this help text and exit\n");
+ printf(" -V, --version print version information and exit\n\n");
+}
+
+static void print_diff_string(const char *str, unsigned int indent_level)
+{
+ const char *c = str;
+ unsigned int i;
+ static const char *indent = " ";
+
+ for (i = 0; i < indent_level; i++)
+ printf("%s", indent);
+ for (; *c; c++) {
+ if (*c == '\n') {
+ if (*(c + 1) == '\0')
+ break;
+ printf("%c", *c);
+ for (i = 0; i < indent_level; i++)
+ printf("%s", indent);
+ } else if (*c == '\t') {
+ printf("%s", indent);
+ } else {
+ printf("%c", *c);
+ }
+ }
+}
+
+static void print_rule_section(const poldiff_t * diff, const poldiff_component_record_t * rec, const apol_vector_t * v,
+ poldiff_form_e form)
+{
+ int i;
+ char *str = NULL;
+ const void *item1;
+
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ item1 = apol_vector_get_element(v, i);
+ if (poldiff_component_record_get_form_fn(rec) (item1) == form) {
+ if ((str = poldiff_component_record_get_to_string_fn(rec) (diff, item1)) == NULL) {
+ return;
+ }
+ print_diff_string(str, 1);
+ printf("\n");
+ free(str);
+ str = NULL;
+ }
+ }
+}
+
+#define PRINT_ADDED_REMOVED 1
+#define PRINT_MODIFIED 2
+#define PRINT_ALL 4
+
+static void print_rule_diffs(const poldiff_t * diff, const poldiff_component_record_t * rec, int stats_only, const char *name,
+ uint32_t flags, apol_vector_comp_func sort_by)
+{
+ const apol_vector_t *internal_v = NULL;
+ apol_vector_t *v = NULL;
+ size_t stats[5] = { 0, 0, 0, 0, 0 };
+
+ if (!rec || !diff)
+ return;
+
+ poldiff_component_record_get_stats_fn(rec) (diff, stats);
+ if (flags == PRINT_ADDED_REMOVED) {
+ printf("%s (Added %zd, Removed %zd)\n", name, stats[0], stats[1]);
+ } else if (flags == PRINT_MODIFIED) {
+ printf("%s (Added %zd, Removed %zd, Modified %zd)\n", name, stats[0], stats[1], stats[2]);
+ } else if (flags == PRINT_ALL) {
+ printf("%s (Added %zd, Added New Type %zd, Removed %zd, Removed Missing Type %zd, Modified %zd)\n", name, stats[0],
+ stats[3], stats[1], stats[4], stats[2]);
+ } else {
+ fprintf(stderr, "Error, unhandled flag type\n");
+ }
+
+ if (stats_only)
+ return;
+ if ((internal_v = poldiff_component_record_get_results_fn(rec) (diff)) == NULL) {
+ return;
+ }
+ if (!(v = apol_vector_create_from_vector(internal_v, NULL, NULL, NULL))) {
+ perror("Error printig results");
+ return;
+ }
+
+ if (sort_by) {
+ apol_vector_sort(v, sort_by, NULL);
+ }
+
+ printf(" Added %s: %zd\n", name, stats[0]);
+ print_rule_section(diff, rec, v, POLDIFF_FORM_ADDED);
+
+ if (flags == PRINT_ALL) {
+ printf(" Added %s because of new type: %zd\n", name, stats[3]);
+ print_rule_section(diff, rec, v, POLDIFF_FORM_ADD_TYPE);
+ }
+
+ printf(" Removed %s: %zd\n", name, stats[1]);
+ print_rule_section(diff, rec, v, POLDIFF_FORM_REMOVED);
+
+ if (flags == PRINT_ALL) {
+ printf(" Removed %s because of missing type: %zd\n", name, stats[4]);
+ print_rule_section(diff, rec, v, POLDIFF_FORM_REMOVE_TYPE);
+ }
+ if (flags == PRINT_MODIFIED || flags == PRINT_ALL) {
+ printf(" Modified %s: %zd\n", name, stats[2]);
+ print_rule_section(diff, rec, v, POLDIFF_FORM_MODIFIED);
+ }
+ printf("\n");
+ apol_vector_destroy(&v);
+ return;
+}
+
+static void print_class_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_CLASSES), stats_only, "Classes", PRINT_MODIFIED, NULL);
+ return;
+}
+
+static void print_bool_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_BOOLS), stats_only, "Booleans", PRINT_MODIFIED, NULL);
+ return;
+}
+
+static void print_common_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_COMMONS), stats_only, "Commons", PRINT_MODIFIED, NULL);
+ return;
+}
+
+static void print_level_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_LEVELS), stats_only, "Levels", PRINT_MODIFIED, NULL);
+ return;
+}
+
+static void print_cat_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_CATS), stats_only, "Categories", PRINT_MODIFIED, NULL);
+ return;
+}
+
+static void print_role_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_ROLES), stats_only, "Roles", PRINT_MODIFIED, NULL);
+ return;
+}
+
+static void print_user_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_USERS), stats_only, "Users", PRINT_MODIFIED, NULL);
+ return;
+}
+
+static void print_avallow_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_AVALLOW), stats_only, "AV-Allow Rules", PRINT_ALL, NULL);
+}
+
+static void print_avauditallow_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_AVAUDITALLOW), stats_only, "AV-Audit Allow Rules",
+ PRINT_ALL, NULL);
+}
+
+static void print_avdontaudit_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_AVDONTAUDIT), stats_only, "AV-Don't Audit Rules",
+ PRINT_ALL, NULL);
+}
+
+static void print_avneverallow_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_AVNEVERALLOW), stats_only, "AV-Never Allow Rules",
+ PRINT_ALL, NULL);
+}
+
+static void print_role_allow_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_ROLE_ALLOWS), stats_only, "Role Allow Rules",
+ PRINT_MODIFIED, NULL);
+}
+
+static void print_role_trans_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_ROLE_TRANS), stats_only, "Role Transitions", PRINT_ALL,
+ NULL);
+}
+
+static void print_range_trans_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_RANGE_TRANS), stats_only, "Range Transitions",
+ PRINT_MODIFIED, NULL);
+}
+
+/** compare the names for two poldiff_type_t objects.
+ * used to sort items prior to display. */
+static int type_name_cmp(const void *a, const void *b, void *user_data __attribute__ ((unused)))
+{
+ poldiff_type_t *ta = (poldiff_type_t *) a;
+ poldiff_type_t *tb = (poldiff_type_t *) b;
+ if (ta == NULL || tb == NULL)
+ return -1;
+ return strcmp(poldiff_type_get_name(ta), poldiff_type_get_name(tb));
+}
+
+static void print_type_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_TYPES), stats_only, "Types", PRINT_MODIFIED,
+ type_name_cmp);
+}
+
+static void print_attrib_diffs(const poldiff_t * diff, int stats_only)
+{
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_ATTRIBS), stats_only, "Attributes", PRINT_MODIFIED, NULL);
+}
+
+static size_t get_diff_total(const poldiff_t * diff, uint32_t flags)
+{
+ size_t total = 0;
+ uint32_t i;
+ size_t stats[5] = { 0, 0, 0, 0, 0 };
+
+ if (!diff || !flags)
+ return 0;
+
+ /* for all 32 bits possible in flags */
+ for (i = 0x80000000; i; i = i >> 1) {
+ if (flags & i) {
+ poldiff_get_stats(diff, i, stats);
+ total += (stats[0] + stats[1] + stats[2] + stats[3] + stats[4]);
+ }
+ }
+
+ return total;
+}
+
+static void print_diff(const poldiff_t * diff, uint32_t flags, int stats, int quiet)
+{
+ if (flags & POLDIFF_DIFF_CLASSES && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_CLASSES))) {
+ print_class_diffs(diff, stats);
+ }
+ if (flags & POLDIFF_DIFF_COMMONS && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_COMMONS))) {
+ print_common_diffs(diff, stats);
+ }
+ if (flags & POLDIFF_DIFF_LEVELS && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_LEVELS))) {
+ print_level_diffs(diff, stats);
+ }
+ if (flags & POLDIFF_DIFF_CATS && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_CATS))) {
+ print_cat_diffs(diff, stats);
+ }
+ if (flags & POLDIFF_DIFF_TYPES && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_TYPES))) {
+ print_type_diffs(diff, stats);
+ }
+ if (flags & POLDIFF_DIFF_ATTRIBS && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_ATTRIBS))) {
+ print_attrib_diffs(diff, stats);
+ }
+ if (flags & POLDIFF_DIFF_ROLES && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_ROLES))) {
+ print_role_diffs(diff, stats);
+ }
+ if (flags & POLDIFF_DIFF_USERS && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_USERS))) {
+ print_user_diffs(diff, stats);
+ }
+ if (flags & POLDIFF_DIFF_BOOLS && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_BOOLS))) {
+ print_bool_diffs(diff, stats);
+ }
+ if (flags & POLDIFF_DIFF_AVALLOW && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_AVALLOW))) {
+ print_avallow_diffs(diff, stats);
+ }
+ if (flags & POLDIFF_DIFF_AVAUDITALLOW && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_AVAUDITALLOW))) {
+ print_avauditallow_diffs(diff, stats);
+ }
+ if (flags & POLDIFF_DIFF_AVDONTAUDIT && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_AVDONTAUDIT))) {
+ print_avdontaudit_diffs(diff, stats);
+ }
+ if (flags & POLDIFF_DIFF_AVNEVERALLOW && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_AVNEVERALLOW))) {
+ print_avneverallow_diffs(diff, stats);
+ }
+ if (flags & POLDIFF_DIFF_TECHANGE && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_TECHANGE))) {
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_TECHANGE), stats, "TE type_change", PRINT_ALL,
+ NULL);
+ }
+ if (flags & POLDIFF_DIFF_TEMEMBER && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_TEMEMBER))) {
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_TEMEMBER), stats, "TE type_member", PRINT_ALL,
+ NULL);
+ }
+ if (flags & POLDIFF_DIFF_TETRANS && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_TETRANS))) {
+ print_rule_diffs(diff, poldiff_get_component_record(POLDIFF_DIFF_TETRANS), stats, "TE type_trans", PRINT_ALL, NULL);
+ }
+ if (flags & POLDIFF_DIFF_ROLE_ALLOWS && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_ROLE_ALLOWS))) {
+ print_role_allow_diffs(diff, stats);
+ }
+ if (flags & POLDIFF_DIFF_ROLE_TRANS && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_ROLE_TRANS))) {
+ print_role_trans_diffs(diff, stats);
+ }
+ if (flags & POLDIFF_DIFF_RANGE_TRANS && !(quiet && !get_diff_total(diff, POLDIFF_DIFF_RANGE_TRANS))) {
+ print_range_trans_diffs(diff, stats);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int optc = 0, quiet = 0, stats = 0, default_all = 0;
+ uint32_t flags = 0;
+ apol_policy_t *orig_policy = NULL, *mod_policy = NULL;
+ apol_policy_path_type_e orig_path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC;
+ char *orig_base_path = NULL;
+ apol_vector_t *orig_module_paths = NULL;
+ apol_policy_path_t *orig_pol_path = NULL;
+ apol_policy_path_type_e mod_path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC;
+ char *mod_base_path = NULL;
+ apol_vector_t *mod_module_paths = NULL;
+ apol_policy_path_t *mod_pol_path = NULL;
+ poldiff_t *diff = NULL;
+ size_t total = 0;
+
+ while ((optc = getopt_long(argc, argv, "ctarubANDLMCRqhV", longopts, NULL)) != -1) {
+ switch (optc) {
+ case 0:
+ break;
+ case 'c':
+ flags |= (POLDIFF_DIFF_CLASSES | POLDIFF_DIFF_COMMONS);
+ break;
+ case DIFF_LEVEL:
+ flags |= POLDIFF_DIFF_LEVELS;
+ break;
+ case DIFF_CATEGORY:
+ flags |= POLDIFF_DIFF_CATS;
+ break;
+ case 't':
+ flags |= POLDIFF_DIFF_TYPES;
+ break;
+ case 'a':
+ flags |= POLDIFF_DIFF_ATTRIBS;
+ break;
+ case 'r':
+ flags |= POLDIFF_DIFF_ROLES;
+ break;
+ case 'u':
+ flags |= POLDIFF_DIFF_USERS;
+ break;
+ case 'b':
+ flags |= POLDIFF_DIFF_BOOLS;
+ break;
+ case 'A':
+ flags |= POLDIFF_DIFF_AVALLOW;
+ break;
+ case DIFF_AUDITALLOW:
+ flags |= POLDIFF_DIFF_AVAUDITALLOW;
+ break;
+ case DIFF_DONTAUDIT:
+ flags |= POLDIFF_DIFF_AVDONTAUDIT;
+ break;
+ case DIFF_NEVERALLOW:
+ flags |= POLDIFF_DIFF_AVNEVERALLOW;
+ break;
+ case DIFF_TYPE_CHANGE:
+ flags |= POLDIFF_DIFF_TECHANGE;
+ break;
+ case DIFF_TYPE_MEMBER:
+ flags |= POLDIFF_DIFF_TEMEMBER;
+ break;
+ case DIFF_TYPE_TRANS:
+ flags |= POLDIFF_DIFF_TETRANS;
+ break;
+ case DIFF_ROLE_ALLOW:
+ flags |= POLDIFF_DIFF_ROLE_ALLOWS;
+ break;
+ case DIFF_ROLE_TRANS:
+ flags |= POLDIFF_DIFF_ROLE_TRANS;
+ break;
+ case DIFF_RANGE_TRANS:
+ flags |= POLDIFF_DIFF_RANGE_TRANS;
+ break;
+ case OPT_STATS:
+ stats = 1;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'h':
+ usage(argv[0], 0);
+ exit(0);
+ case 'V':
+ printf("sediff %s\n%s\n", VERSION, COPYRIGHT_INFO);
+ exit(0);
+ default:
+ usage(argv[0], 1);
+ exit(1);
+ }
+ }
+
+ if (!flags) {
+ flags = POLDIFF_DIFF_ALL & ~POLDIFF_DIFF_AVNEVERALLOW;
+ default_all = 1;
+ }
+
+ if (argc - optind < 2) {
+ usage(argv[0], 1);
+ exit(1);
+ }
+
+ if (!strcmp(";", argv[optind])) {
+ ERR(NULL, "%s", "Missing path to original policy.");
+ goto err;
+ }
+ orig_base_path = argv[optind++];
+ orig_path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC;
+ if (!(orig_module_paths = apol_vector_create(NULL))) {
+ ERR(NULL, "%s", strerror(errno));
+ goto err;
+ }
+ for (; argc - optind; optind++) {
+ if (!strcmp(";", argv[optind])) {
+ optind++;
+ break;
+ }
+ if (apol_vector_append(orig_module_paths, (void *)argv[optind])) {
+ ERR(NULL, "Error loading module %s", argv[optind]);
+ goto err;
+ }
+ orig_path_type = APOL_POLICY_PATH_TYPE_MODULAR;
+ }
+ if (apol_file_is_policy_path_list(orig_base_path) > 0) {
+ orig_pol_path = apol_policy_path_create_from_file(orig_base_path);
+ if (!orig_pol_path) {
+ ERR(NULL, "%s", "invalid policy list");
+ goto err;
+ }
+ } else {
+ orig_pol_path = apol_policy_path_create(orig_path_type, orig_base_path, orig_module_paths);
+ if (!orig_pol_path) {
+ ERR(NULL, "%s", strerror(errno));
+ goto err;
+ }
+ }
+ apol_vector_destroy(&orig_module_paths);
+
+ if (argc - optind == 0) {
+ ERR(NULL, "%s", "Missing path to modified policy.");
+ goto err;
+ }
+
+ mod_base_path = argv[optind++];
+ mod_path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC;
+ if (!(mod_module_paths = apol_vector_create(NULL))) {
+ ERR(NULL, "%s", strerror(errno));
+ goto err;
+ }
+ for (; argc - optind; optind++) {
+ if (apol_vector_append(mod_module_paths, (void *)argv[optind])) {
+ ERR(NULL, "Error loading module %s", argv[optind]);
+ goto err;
+ }
+ mod_path_type = APOL_POLICY_PATH_TYPE_MODULAR;
+ }
+ if (apol_file_is_policy_path_list(mod_base_path) > 0) {
+ mod_pol_path = apol_policy_path_create_from_file(mod_base_path);
+ if (!mod_pol_path) {
+ ERR(NULL, "%s", "invalid policy list");
+ goto err;
+ }
+ } else {
+ mod_pol_path = apol_policy_path_create(mod_path_type, mod_base_path, mod_module_paths);
+ if (!mod_pol_path) {
+ ERR(NULL, "%s", strerror(errno));
+ goto err;
+ }
+ }
+ apol_vector_destroy(&mod_module_paths);
+
+ int policy_opt = 0;
+ if (!(flags & POLDIFF_DIFF_AVNEVERALLOW)) {
+ policy_opt |= QPOL_POLICY_OPTION_NO_NEVERALLOWS;
+ }
+ if (!(flags & POLDIFF_DIFF_RULES)) {
+ policy_opt |= QPOL_POLICY_OPTION_NO_RULES;
+ }
+ orig_policy = apol_policy_create_from_policy_path(orig_pol_path, policy_opt, NULL, NULL);
+ if (!orig_policy) {
+ ERR(NULL, "%s", strerror(errno));
+ goto err;
+ }
+ mod_policy = apol_policy_create_from_policy_path(mod_pol_path, policy_opt, NULL, NULL);
+ if (!mod_policy) {
+ ERR(NULL, "%s", strerror(errno));
+ goto err;
+ }
+
+ qpol_policy_t *orig_qpol = apol_policy_get_qpol(orig_policy);
+ qpol_policy_t *mod_qpol = apol_policy_get_qpol(mod_policy);
+ /* we disable attribute diffs if either policy does not
+ * support attribute names because the fake attribute names
+ * won't make sense */
+ if ((flags & POLDIFF_DIFF_ATTRIBS)
+ && (!(qpol_policy_has_capability(orig_qpol, QPOL_CAP_ATTRIB_NAMES))
+ || !(qpol_policy_has_capability(mod_qpol, QPOL_CAP_ATTRIB_NAMES)))) {
+ flags &= ~POLDIFF_DIFF_ATTRIBS;
+ WARN(NULL, "%s", "Attribute diffs are not supported for current policies.");
+ }
+
+ /* we disable MLS diffs if both policies do not support MLS
+ * but do not warn if it was implicitly requested for two
+ * non-MLS policies */
+ if ((flags & POLDIFF_DIFF_MLS)
+ && (!(qpol_policy_has_capability(orig_qpol, QPOL_CAP_MLS)) && !(qpol_policy_has_capability(mod_qpol, QPOL_CAP_MLS)))) {
+ flags &= ~(POLDIFF_DIFF_MLS);
+ if (!default_all) {
+ WARN(NULL, "%s", "MLS diffs are not supported for current policies.");
+ }
+ }
+
+ /* default callback for error handling is sufficient here */
+ if (!(diff = poldiff_create(orig_policy, mod_policy, NULL, NULL))) {
+ ERR(NULL, "%s", strerror(errno));
+ goto err;
+ }
+ /* poldiff now owns the policies */
+ orig_policy = mod_policy = NULL;
+
+ if (poldiff_run(diff, flags)) {
+ goto err;
+ }
+
+ print_diff(diff, flags, stats, quiet);
+
+ total = get_diff_total(diff, flags);
+
+ apol_policy_path_destroy(&orig_pol_path);
+ apol_policy_path_destroy(&mod_pol_path);
+ poldiff_destroy(&diff);
+
+ if (total)
+ return 1;
+ else
+ return 0;
+
+ err:
+ apol_policy_destroy(&orig_policy);
+ apol_policy_destroy(&mod_policy);
+ apol_policy_path_destroy(&orig_pol_path);
+ apol_policy_path_destroy(&mod_pol_path);
+ apol_vector_destroy(&orig_module_paths);
+ apol_vector_destroy(&mod_module_paths);
+ poldiff_destroy(&diff);
+ return 1;
+}