13fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman#include <getopt.h>
23fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman#include <sepol/policydb/expand.h>
33fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
43fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman#include "typecmp.h"
53fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
63fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashmanvoid typecmp_usage() {
73fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    fprintf(stderr, "\ttypecmp [-d|--diff] [-e|--equiv]\n");
83fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman}
93fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
103fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashmanstatic int insert_type_rule(avtab_key_t * k, avtab_datum_t * d,
113fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                            struct avtab_node *type_rules)
123fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman{
133fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    struct avtab_node *p, *c, *n;
143fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
153fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) {
163fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        /*
173fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman         * Find the insertion point, keeping the list
183fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman         * ordered by source type, then target type, then
193fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman         * target class.
203fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman         */
213fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        if (k->source_type < c->key.source_type)
223fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            break;
233fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        if (k->source_type == c->key.source_type &&
243fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            k->target_type < c->key.target_type)
253fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            break;
263fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        if (k->source_type == c->key.source_type &&
273fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            k->target_type == c->key.target_type &&
283fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            k->target_class <= c->key.target_class)
293fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            break;
303fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    }
313fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
323fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if (c &&
333fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        k->source_type == c->key.source_type &&
343fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        k->target_type == c->key.target_type &&
353fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        k->target_class == c->key.target_class) {
363fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        c->datum.data |= d->data;
373fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        return 0;
383fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    }
393fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
403fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    /* Insert the rule */
413fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    n = malloc(sizeof(struct avtab_node));
423fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if (!n) {
433fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        fprintf(stderr, "out of memory\n");
443fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        exit(1);
453fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    }
463fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
473fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    n->key = *k;
483fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    n->datum = *d;
493fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    n->next = p->next;
503fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    p->next = n;
513fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    return 0;
523fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman}
533fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
543fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashmanstatic int create_type_rules_helper(avtab_key_t * k, avtab_datum_t * d,
553fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                                    void *args)
563fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman{
573fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    struct avtab_node *type_rules = args;
583fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    avtab_key_t key;
593fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
603fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    /*
613fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     * Insert the rule into the list for
623fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     * the source type.  The source type value
633fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     * is cleared as we want to compare against other type
643fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     * rules with different source types.
653fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     */
663fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    key = *k;
673fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    key.source_type = 0;
683fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if (k->source_type == k->target_type) {
693fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        /* Clear target type as well; this is a self rule. */
703fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        key.target_type = 0;
713fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    }
723fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if (insert_type_rule(&key, d, &type_rules[k->source_type - 1]))
733fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        return -1;
743fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
753fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if (k->source_type == k->target_type)
763fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        return 0;
773fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
783fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    /*
793fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     * If the target type differs, then we also
803fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     * insert the rule into the list for the target
813fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     * type.  We clear the target type value so that
823fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     * we can compare against other type rules with
833fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     * different target types.
843fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     */
853fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    key = *k;
863fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    key.target_type = 0;
873fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if (insert_type_rule(&key, d, &type_rules[k->target_type - 1]))
883fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        return -1;
893fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
903fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    return 0;
913fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman}
923fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
933fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashmanstatic int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args)
943fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman{
953fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if (k->specified & AVTAB_ALLOWED)
963fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        return create_type_rules_helper(k, d, args);
973fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    return 0;
983fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman}
993fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
1003fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashmanstatic int create_type_rules_cond(avtab_key_t * k, avtab_datum_t * d,
1013fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                                  void *args)
1023fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman{
1033fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if ((k->specified & (AVTAB_ALLOWED|AVTAB_ENABLED)) ==
1043fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        (AVTAB_ALLOWED|AVTAB_ENABLED))
1053fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        return create_type_rules_helper(k, d, args);
1063fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    return 0;
1073fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman}
1083fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
1093fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashmanstatic void free_type_rules(struct avtab_node *l)
1103fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman{
1113fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    struct avtab_node *tmp;
1123fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
1133fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    while (l) {
1143fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        tmp = l;
1153fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        l = l->next;
1163fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        free(tmp);
1173fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    }
1183fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman}
1193fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
1203fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashmanstatic int find_match(policydb_t *policydb, struct avtab_node *l1,
1213fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                      int idx1, struct avtab_node *l2, int idx2)
1223fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman{
1233fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    struct avtab_node *c;
1243fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    uint32_t perms1, perms2;
1253fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
1263fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    for (c = l2; c; c = c->next) {
1273fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        if (l1->key.source_type < c->key.source_type)
1283fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            break;
1293fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        if (l1->key.source_type == c->key.source_type &&
1303fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            l1->key.target_type < c->key.target_type)
1313fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            break;
1323fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        if (l1->key.source_type == c->key.source_type &&
1333fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            l1->key.target_type == c->key.target_type &&
1343fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            l1->key.target_class <= c->key.target_class)
1353fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            break;
1363fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    }
1373fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
1383fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if (c &&
1393fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        l1->key.source_type == c->key.source_type &&
1403fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        l1->key.target_type == c->key.target_type &&
1413fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        l1->key.target_class == c->key.target_class) {
1423fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        perms1 = l1->datum.data & ~c->datum.data;
1433fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        perms2 = c->datum.data & ~l1->datum.data;
1443fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        if (perms1 || perms2) {
1453fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            if (perms1)
1463fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                display_allow(policydb, &l1->key, idx1, perms1);
1473fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            if (perms2)
1483fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                display_allow(policydb, &c->key, idx2, perms2);
1493fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            printf("\n");
1503fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            return 1;
1513fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        }
1523fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    }
1533fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
1543fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    return 0;
1553fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman}
1563fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
1573fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashmanstatic int analyze_types(policydb_t * policydb, char diff, char equiv)
1583fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman{
1593fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    avtab_t exp_avtab, exp_cond_avtab;
1603fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    struct avtab_node *type_rules, *l1, *l2;
1613fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    struct type_datum *type;
1623fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    size_t i, j;
1633fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
1643fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    /*
1653fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     * Create a list of access vector rules for each type
1663fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     * from the access vector table.
1673fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     */
1683fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    type_rules = malloc(sizeof(struct avtab_node) * policydb->p_types.nprim);
1693fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if (!type_rules) {
1703fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        fprintf(stderr, "out of memory\n");
1713fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        exit(1);
1723fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    }
1733fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    memset(type_rules, 0, sizeof(struct avtab_node) * policydb->p_types.nprim);
1743fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
1753fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if (avtab_init(&exp_avtab) || avtab_init(&exp_cond_avtab)) {
1763fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        fputs("out of memory\n", stderr);
1773fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        return -1;
1783fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    }
1793fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
1803fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if (expand_avtab(policydb, &policydb->te_avtab, &exp_avtab)) {
1813fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        fputs("out of memory\n", stderr);
1823fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        avtab_destroy(&exp_avtab);
1833fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        return -1;
1843fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    }
1853fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
1863fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if (expand_avtab(policydb, &policydb->te_cond_avtab, &exp_cond_avtab)) {
1873fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        fputs("out of memory\n", stderr);
1883fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        avtab_destroy(&exp_avtab); /*  */
1893fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        return -1;
1903fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    }
1913fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
1923fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if (avtab_map(&exp_avtab, create_type_rules, type_rules))
1933fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        exit(1);
1943fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
1953fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if (avtab_map(&exp_cond_avtab, create_type_rules_cond, type_rules))
1963fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        exit(1);
1973fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
1983fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    avtab_destroy(&exp_avtab);
1993fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    avtab_destroy(&exp_cond_avtab);
2003fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
2013fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    /*
2023fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     * Compare the type lists and identify similar types.
2033fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman     */
2043fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    for (i = 0; i < policydb->p_types.nprim - 1; i++) {
2053fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        if (!type_rules[i].next)
2063fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            continue;
2073fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        type = policydb->type_val_to_struct[i];
2083fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        if (type->flavor) {
2093fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            free_type_rules(type_rules[i].next);
2103fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            type_rules[i].next = NULL;
2113fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            continue;
2123fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        }
2133fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        for (j = i + 1; j < policydb->p_types.nprim; j++) {
2143fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            type = policydb->type_val_to_struct[j];
2153fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            if (type->flavor) {
2163fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                free_type_rules(type_rules[j].next);
2173fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                type_rules[j].next = NULL;
2183fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                continue;
2193fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            }
2203fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            for (l1 = type_rules[i].next, l2 = type_rules[j].next;
2213fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                 l1 && l2; l1 = l1->next, l2 = l2->next) {
2223fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                if (l1->key.source_type != l2->key.source_type)
2233fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                    break;
2243fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                if (l1->key.target_type != l2->key.target_type)
2253fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                    break;
2263fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                if (l1->key.target_class != l2->key.target_class
2273fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                    || l1->datum.data != l2->datum.data)
2283fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                    break;
2293fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            }
2303fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            if (l1 || l2) {
2313fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                if (diff) {
2323fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                    printf
2333fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                        ("Types %s and %s differ, starting with:\n",
2343fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                         policydb->p_type_val_to_name[i],
2353fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                         policydb->p_type_val_to_name[j]);
2363fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
2373fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                    if (l1 && l2) {
2383fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                        if (find_match(policydb, l1, i, l2, j))
2393fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                            continue;
2403fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                        if (find_match(policydb, l2, j, l1, i))
2413fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                            continue;
2423fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                    }
2433fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                    if (l1)
2443fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                        display_allow(policydb, &l1->key, i, l1->datum.data);
2453fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                    if (l2)
2463fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                        display_allow(policydb, &l2->key, j, l2->datum.data);
2473fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                    printf("\n");
2483fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                }
2493fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                continue;
2503fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            }
2513fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            free_type_rules(type_rules[j].next);
2523fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            type_rules[j].next = NULL;
2533fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            if (equiv) {
2543fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                printf("Types %s and %s are equivalent.\n",
2553fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                       policydb->p_type_val_to_name[i],
2563fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman                       policydb->p_type_val_to_name[j]);
2573fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            }
2583fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        }
2593fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        free_type_rules(type_rules[i].next);
2603fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        type_rules[i].next = NULL;
2613fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    }
2623fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
2633fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    free(type_rules);
2643fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    return 0;
2653fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman}
2663fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
2673fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashmanint typecmp_func (int argc, char **argv, policydb_t *policydb) {
2683fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    char ch, diff = 0, equiv = 0;
2693fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
2703fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    struct option typecmp_options[] = {
2713fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        {"diff", no_argument, NULL, 'd'},
2723fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        {"equiv", no_argument, NULL, 'e'},
2733fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        {NULL, 0, NULL, 0}
2743fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    };
2753fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
2763fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    while ((ch = getopt_long(argc, argv, "de", typecmp_options, NULL)) != -1) {
2773fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        switch (ch) {
2783fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        case 'd':
2793fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            diff = 1;
2803fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            break;
2813fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        case 'e':
2823fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            equiv = 1;
2833fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            break;
2843fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        default:
2853fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            USAGE_ERROR = true;
2863fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman            return -1;
2873fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        }
2883fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    }
2893fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman
2903fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    if (!(diff || equiv)) {
2913fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        USAGE_ERROR = true;
2923fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman        return -1;
2933fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    }
2943fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman    return analyze_types(policydb, diff, equiv);
2953fa92beda7ee062b15f6b214bdc7e5f6a71df28edcashman}
296