Home | History | Annotate | Download | only in bin
      1 #!/usr/bin/env python
      2 # Copyright 2015-2016, Tresys Technology, LLC
      3 #
      4 # This file is part of SETools.
      5 #
      6 # SETools is free software: you can redistribute it and/or modify
      7 # it under the terms of the GNU General Public License as published by
      8 # the Free Software Foundation, either version 2 of the License, or
      9 # (at your option) any later version.
     10 #
     11 # SETools is distributed in the hope that it will be useful,
     12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 # GNU General Public License for more details.
     15 #
     16 # You should have received a copy of the GNU General Public License
     17 # along with SETools.  If not, see <http://www.gnu.org/licenses/>.
     18 #
     19 
     20 from __future__ import print_function
     21 import setools
     22 import argparse
     23 import sys
     24 import logging
     25 from itertools import chain
     26 
     27 parser = argparse.ArgumentParser(
     28     description="SELinux policy semantic difference tool.",
     29     epilog="If no differences are selected, all differences will be printed.")
     30 parser.add_argument("POLICY1", help="Path to the first SELinux policy to diff.", nargs=1)
     31 parser.add_argument("POLICY2", help="Path to the second SELinux policy to diff.", nargs=1)
     32 parser.add_argument("--version", action="version", version=setools.__version__)
     33 parser.add_argument("--stats", action="store_true", help="Display only statistics.")
     34 parser.add_argument("-v", "--verbose", action="store_true",
     35                     help="Print extra informational messages")
     36 parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.")
     37 
     38 comp = parser.add_argument_group("component differences")
     39 comp.add_argument("--common", action="store_true", help="Print common differences")
     40 comp.add_argument("-c", "--class", action="store_true", help="Print class differences",
     41                   dest="class_")
     42 comp.add_argument("-t", "--type", action="store_true", help="Print type differences",
     43                   dest="type_")
     44 comp.add_argument("-a", "--attribute", action="store_true", help="Print type attribute differences")
     45 comp.add_argument("-r", "--role", action="store_true", help="Print role differences")
     46 comp.add_argument("-u", "--user", action="store_true", help="Print user differences")
     47 comp.add_argument("-b", "--bool", action="store_true", help="Print Boolean differences",
     48                   dest="bool_")
     49 comp.add_argument("--sensitivity", action="store_true", help="Print MLS sensitivity differences")
     50 comp.add_argument("--category", action="store_true", help="Print MLS category differences")
     51 comp.add_argument("--level", action="store_true", help="Print MLS level definition differences")
     52 
     53 terule = parser.add_argument_group("type enforcement rule differences")
     54 terule.add_argument("-A", action="store_true", help="Print allow and allowxperm rule differences")
     55 terule.add_argument("--allow", action="store_true", help="Print allow rule differences")
     56 terule.add_argument("--neverallow", action="store_true", help="Print neverallow rule differences")
     57 terule.add_argument("--auditallow", action="store_true", help="Print auditallow rule differences")
     58 terule.add_argument("--dontaudit", action="store_true", help="Print dontaudit rule differences")
     59 terule.add_argument("--allowxperm", action="store_true", help="Print allowxperm rule differences")
     60 terule.add_argument("--neverallowxperm", action="store_true",
     61                     help="Print neverallowxperm rule differences")
     62 terule.add_argument("--auditallowxperm", action="store_true",
     63                     help="Print auditallowxperm rule differences")
     64 terule.add_argument("--dontauditxperm", action="store_true",
     65                     help="Print dontauditxperm rule differences")
     66 terule.add_argument("-T", "--type_trans", action="store_true",
     67                     help="Print type_transition rule differences")
     68 terule.add_argument("--type_change", action="store_true", help="Print type_change rule differences")
     69 terule.add_argument("--type_member", action="store_true",
     70                     help="Print type_member rule differences")
     71 
     72 rbacrule = parser.add_argument_group("RBAC rule differences")
     73 rbacrule.add_argument("--role_allow", action="store_true", help="Print role allow rule differences")
     74 rbacrule.add_argument("--role_trans", action="store_true",
     75                       help="Print role_transition rule differences")
     76 
     77 mlsrule = parser.add_argument_group("MLS rule differences")
     78 mlsrule.add_argument("--range_trans", action="store_true",
     79                      help="Print range_transition rule differences")
     80 
     81 constrain = parser.add_argument_group("Constraint differences")
     82 constrain.add_argument("--constrain", action="store_true", help="Print constrain differences")
     83 constrain.add_argument("--mlsconstrain", action="store_true", help="Print mlsconstrain differences")
     84 constrain.add_argument("--validatetrans", action="store_true",
     85                        help="Print validatetrans differences")
     86 constrain.add_argument("--mlsvalidatetrans", action="store_true",
     87                        help="Print mlsvalidatetrans differences")
     88 
     89 labeling = parser.add_argument_group("labeling statement differences")
     90 labeling.add_argument("--initialsid", action="store_true", help="Print initial SID differences")
     91 labeling.add_argument("--fs_use", action="store_true", help="Print fs_use_* differences")
     92 labeling.add_argument("--genfscon", action="store_true", help="Print genfscon differences")
     93 labeling.add_argument("--netifcon", action="store_true", help="Print netifcon differences")
     94 labeling.add_argument("--nodecon", action="store_true", help="Print nodecon differences")
     95 labeling.add_argument("--portcon", action="store_true", help="Print portcon differences")
     96 
     97 other = parser.add_argument_group("other differences")
     98 other.add_argument("--default", action="store_true", help="Print default_* differences")
     99 other.add_argument("--property", action="store_true",
    100                    help="Print policy property differences (handle_unknown, version, MLS)")
    101 other.add_argument("--polcap", action="store_true", help="Print policy capability differences")
    102 other.add_argument("--typebounds", action="store_true", help="Print typebounds differences")
    103 
    104 args = parser.parse_args()
    105 
    106 if args.A:
    107     args.allow = True
    108     args.allowxperm = True
    109 
    110 all_differences = not any((args.class_, args.common, args.type_, args.attribute, args.role,
    111                            args.user, args.bool_, args.sensitivity, args.category, args.level,
    112                            args.allow, args.neverallow, args.auditallow, args.dontaudit,
    113                            args.type_trans, args.type_change, args.type_member, args.role_allow,
    114                            args.role_trans, args.range_trans, args.initialsid, args.genfscon,
    115                            args.netifcon, args.nodecon, args.portcon, args.fs_use, args.polcap,
    116                            args.property, args.default, args.constrain, args.mlsconstrain,
    117                            args.validatetrans, args.mlsvalidatetrans, args.typebounds,
    118                            args.allowxperm, args.neverallowxperm, args.auditallowxperm,
    119                            args.dontauditxperm))
    120 
    121 if args.debug:
    122     logging.basicConfig(level=logging.DEBUG,
    123                         format='%(asctime)s|%(levelname)s|%(name)s|%(message)s')
    124 elif args.verbose:
    125     logging.basicConfig(level=logging.INFO, format='%(message)s')
    126 else:
    127     logging.basicConfig(level=logging.WARNING, format='%(message)s')
    128 
    129 try:
    130     p1 = setools.SELinuxPolicy(args.POLICY1[0])
    131     p2 = setools.SELinuxPolicy(args.POLICY2[0])
    132     diff = setools.PolicyDifference(p1, p2)
    133 
    134     if all_differences or args.property:
    135         print("Policy Properties ({0} Modified)".format(len(diff.modified_properties)))
    136 
    137         if diff.modified_properties and not args.stats:
    138             for name, added, removed in sorted(diff.modified_properties, key=lambda x: x.property):
    139                 print("      * {0} +{1} -{2}".format(name, added, removed))
    140 
    141         print()
    142 
    143     if all_differences or args.common:
    144         if diff.added_commons or diff.removed_commons or diff.modified_commons or args.common:
    145             print("Commons ({0} Added, {1} Removed, {2} Modified)".format(
    146                 len(diff.added_commons), len(diff.removed_commons), len(diff.modified_commons)))
    147             if diff.added_commons and not args.stats:
    148                 print("   Added Commons: {0}".format(len(diff.added_commons)))
    149                 for c in sorted(diff.added_commons):
    150                     print("      + {0}".format(c))
    151             if diff.removed_commons and not args.stats:
    152                 print("   Removed Commons: {0}".format(len(diff.removed_commons)))
    153                 for c in sorted(diff.removed_commons):
    154                     print("      - {0}".format(c))
    155             if diff.modified_commons and not args.stats:
    156                 print("   Modified Commons: {0}".format(len(diff.modified_commons)))
    157                 for name, mod in sorted(diff.modified_commons.items()):
    158                     change = []
    159                     if mod.added_perms:
    160                         change.append("{0} Added permissions".format(len(mod.added_perms)))
    161                     if mod.removed_perms:
    162                         change.append("{0} Removed permissions".format(len(mod.removed_perms)))
    163 
    164                     print("      * {0} ({1})".format(name, ", ".join(change)))
    165                     for p in sorted(mod.added_perms):
    166                         print("          + {0}".format(p))
    167                     for p in sorted(mod.removed_perms):
    168                         print("          - {0}".format(p))
    169             print()
    170 
    171     if all_differences or args.class_:
    172         if diff.added_classes or diff.removed_classes or diff.modified_classes or args.class_:
    173             print("Classes ({0} Added, {1} Removed, {2} Modified)".format(
    174                 len(diff.added_classes), len(diff.removed_classes), len(diff.modified_classes)))
    175             if diff.added_classes and not args.stats:
    176                 print("   Added Classes: {0}".format(len(diff.added_classes)))
    177                 for c in sorted(diff.added_classes):
    178                     print("      + {0}".format(c))
    179             if diff.removed_classes and not args.stats:
    180                 print("   Removed Classes: {0}".format(len(diff.removed_classes)))
    181                 for c in sorted(diff.removed_classes):
    182                     print("      - {0}".format(c))
    183             if diff.modified_classes and not args.stats:
    184                 print("   Modified Classes: {0}".format(len(diff.modified_classes)))
    185                 for name, mod in sorted(diff.modified_classes.items()):
    186                     change = []
    187                     if mod.added_perms:
    188                         change.append("{0} Added permissions".format(len(mod.added_perms)))
    189                     if mod.removed_perms:
    190                         change.append("{0} Removed permissions".format(len(mod.removed_perms)))
    191 
    192                     print("      * {0} ({1})".format(name, ", ".join(change)))
    193                     for p in sorted(mod.added_perms):
    194                         print("          + {0}".format(p))
    195                     for p in sorted(mod.removed_perms):
    196                         print("          - {0}".format(p))
    197             print()
    198 
    199     if all_differences or args.bool_:
    200         if diff.added_booleans or diff.removed_booleans or \
    201                 diff.modified_booleans or args.bool_:
    202             print("Booleans ({0} Added, {1} Removed, {2} Modified)".format(
    203                 len(diff.added_booleans), len(diff.removed_booleans),
    204                 len(diff.modified_booleans)))
    205             if diff.added_booleans and not args.stats:
    206                 print("   Added Booleans: {0}".format(len(diff.added_booleans)))
    207                 for a in sorted(diff.added_booleans):
    208                     print("      + {0}".format(a))
    209             if diff.removed_booleans and not args.stats:
    210                 print("   Removed Booleans: {0}".format(len(diff.removed_booleans)))
    211                 for a in sorted(diff.removed_booleans):
    212                     print("      - {0}".format(a))
    213             if diff.modified_booleans and not args.stats:
    214                 print("   Modified Booleans: {0}".format(len(diff.modified_booleans)))
    215                 for name, mod in sorted(diff.modified_booleans.items()):
    216                     print("      * {0} (Modified default state)".format(name))
    217                     print("          + {0}".format(mod.added_state))
    218                     print("          - {0}".format(mod.removed_state))
    219 
    220             print()
    221 
    222     if all_differences or args.role:
    223         if diff.added_roles or diff.removed_roles or diff.modified_roles or args.role:
    224             print("Roles ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_roles),
    225                                                                         len(diff.removed_roles),
    226                                                                         len(diff.modified_roles)))
    227             if diff.added_roles and not args.stats:
    228                 print("   Added Roles: {0}".format(len(diff.added_roles)))
    229                 for r in sorted(diff.added_roles):
    230                     print("      + {0}".format(r))
    231             if diff.removed_roles and not args.stats:
    232                 print("   Removed Roles: {0}".format(len(diff.removed_roles)))
    233                 for r in sorted(diff.removed_roles):
    234                     print("      - {0}".format(r))
    235             if diff.modified_roles and not args.stats:
    236                 print("   Modified Roles: {0}".format(len(diff.modified_roles)))
    237                 for name, mod in sorted(diff.modified_roles.items()):
    238                     change = []
    239                     if mod.added_types:
    240                         change.append("{0} Added types".format(len(mod.added_types)))
    241                     if mod.removed_types:
    242                         change.append("{0} Removed types".format(len(mod.removed_types)))
    243 
    244                     print("      * {0} ({1})".format(name, ", ".join(change)))
    245                     for t in sorted(mod.added_types):
    246                         print("          + {0}".format(t))
    247                     for t in sorted(mod.removed_types):
    248                         print("          - {0}".format(t))
    249             print()
    250 
    251     if all_differences or args.type_:
    252         if diff.added_types or diff.removed_types or diff.modified_types or args.type_:
    253             print("Types ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_types),
    254                                                                         len(diff.removed_types),
    255                                                                         len(diff.modified_types)))
    256             if diff.added_types and not args.stats:
    257                 print("   Added Types: {0}".format(len(diff.added_types)))
    258                 for r in sorted(diff.added_types):
    259                     print("      + {0}".format(r))
    260             if diff.removed_types and not args.stats:
    261                 print("   Removed Types: {0}".format(len(diff.removed_types)))
    262                 for r in sorted(diff.removed_types):
    263                     print("      - {0}".format(r))
    264             if diff.modified_types and not args.stats:
    265                 print("   Modified Types: {0}".format(len(diff.modified_types)))
    266                 for name, mod in sorted(diff.modified_types.items()):
    267                     change = []
    268                     if mod.added_attributes:
    269                         change.append("{0} Added attributes".format(len(mod.added_attributes)))
    270                     if mod.removed_attributes:
    271                         change.append("{0} Removed attributes".format(len(mod.removed_attributes)))
    272                     if mod.added_aliases:
    273                         change.append("{0} Added aliases".format(len(mod.added_aliases)))
    274                     if mod.removed_aliases:
    275                         change.append("{0} Removed aliases".format(len(mod.removed_aliases)))
    276                     if mod.modified_permissive:
    277                         if mod.permissive:
    278                             change.append("Removed permissive")
    279                         else:
    280                             change.append("Added permissive")
    281 
    282                     print("      * {0} ({1})".format(name, ", ".join(change)))
    283                     if mod.added_attributes or mod.removed_attributes:
    284                         print("          Attributes:")
    285                     for t in sorted(mod.added_attributes):
    286                         print("          + {0}".format(t))
    287                     for t in sorted(mod.removed_attributes):
    288                         print("          - {0}".format(t))
    289 
    290                     if mod.added_aliases or mod.removed_aliases:
    291                         print("          Aliases:")
    292                     for t in sorted(mod.added_aliases):
    293                         print("          + {0}".format(t))
    294                     for t in sorted(mod.removed_aliases):
    295                         print("          - {0}".format(t))
    296 
    297             print()
    298 
    299     if all_differences or args.attribute:
    300         if diff.added_type_attributes or diff.removed_type_attributes or \
    301                 diff.modified_type_attributes or args.attribute:
    302             print("Type Attributes ({0} Added, {1} Removed, {2} Modified)".format(
    303                 len(diff.added_type_attributes), len(diff.removed_type_attributes),
    304                 len(diff.modified_type_attributes)))
    305             if diff.added_type_attributes and not args.stats:
    306                 print("   Added Type Attributes: {0}".format(len(diff.added_type_attributes)))
    307                 for a in sorted(diff.added_type_attributes):
    308                     print("      + {0}".format(a))
    309             if diff.removed_type_attributes and not args.stats:
    310                 print("   Removed Type Attributes: {0}".format(len(diff.removed_type_attributes)))
    311                 for a in sorted(diff.removed_type_attributes):
    312                     print("      - {0}".format(a))
    313             if diff.modified_type_attributes and not args.stats:
    314                 print("   Modified Type Attributes: {0}".format(len(diff.modified_type_attributes)))
    315                 for name, mod in sorted(diff.modified_type_attributes.items()):
    316                     change = []
    317                     if mod.added_types:
    318                         change.append("{0} Added types".format(len(mod.added_types)))
    319                     if mod.removed_types:
    320                         change.append("{0} Removed types".format(len(mod.removed_types)))
    321 
    322                     print("      * {0} ({1})".format(name, ", ".join(change)))
    323                     for t in sorted(mod.added_types):
    324                         print("          + {0}".format(t))
    325                     for t in sorted(mod.removed_types):
    326                         print("          - {0}".format(t))
    327             print()
    328 
    329     if all_differences or args.user:
    330         if diff.added_users or diff.removed_users or diff.modified_users or args.user:
    331             print("Users ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_users),
    332                                                                         len(diff.removed_users),
    333                                                                         len(diff.modified_users)))
    334             if diff.added_users and not args.stats:
    335                 print("   Added Users: {0}".format(len(diff.added_users)))
    336                 for u in sorted(diff.added_users):
    337                     print("      + {0}".format(u))
    338             if diff.removed_users and not args.stats:
    339                 print("   Removed Users: {0}".format(len(diff.removed_users)))
    340                 for u in sorted(diff.removed_users):
    341                     print("      - {0}".format(u))
    342             if diff.modified_users and not args.stats:
    343                 print("   Modified Users: {0}".format(len(diff.modified_users)))
    344                 for name, mod in sorted(diff.modified_users.items()):
    345                     change = []
    346                     if mod.added_roles:
    347                         change.append("{0} Added roles".format(len(mod.added_roles)))
    348                     if mod.removed_roles:
    349                         change.append("{0} Removed roles".format(len(mod.removed_roles)))
    350                     if mod.removed_level:
    351                         change.append("Modified default level")
    352                     if mod.removed_range:
    353                         change.append("Modified range")
    354 
    355                     print("      * {0} ({1})".format(name, ", ".join(change)))
    356                     if mod.added_roles or mod.removed_roles:
    357                         print("          Roles:")
    358                     for t in sorted(mod.added_roles):
    359                         print("          + {0}".format(t))
    360                     for t in sorted(mod.removed_roles):
    361                         print("          - {0}".format(t))
    362 
    363                     if mod.removed_level:
    364                         print("          Default level:")
    365                         print("          + {0}".format(mod.added_level))
    366                         print("          - {0}".format(mod.removed_level))
    367 
    368                     if mod.removed_range:
    369                         print("          Range:")
    370                         print("          + {0}".format(mod.added_range))
    371                         print("          - {0}".format(mod.removed_range))
    372             print()
    373 
    374     if all_differences or args.category:
    375         if diff.added_categories or diff.removed_categories or diff.modified_categories \
    376                 or args.category:
    377             print("Categories ({0} Added, {1} Removed, {2} Modified)".format(
    378                 len(diff.added_categories), len(diff.removed_categories),
    379                 len(diff.modified_categories)))
    380             if diff.added_categories and not args.stats:
    381                 print("   Added Categories: {0}".format(len(diff.added_categories)))
    382                 for c in sorted(diff.added_categories):
    383                     print("      + {0}".format(c))
    384             if diff.removed_categories and not args.stats:
    385                 print("   Removed Categories: {0}".format(len(diff.removed_categories)))
    386                 for c in sorted(diff.removed_categories):
    387                     print("      - {0}".format(c))
    388             if diff.modified_categories and not args.stats:
    389                 print("   Modified Categories: {0}".format(len(diff.modified_categories)))
    390                 for name, mod in sorted(diff.modified_categories.items()):
    391                     change = []
    392                     if mod.added_aliases:
    393                         change.append("{0} Added Aliases".format(len(mod.added_aliases)))
    394                     if mod.removed_aliases:
    395                         change.append("{0} Removed Aliases".format(len(mod.removed_aliases)))
    396 
    397                     print("      * {0} ({1})".format(name, ", ".join(change)))
    398                     print("          Aliases:")
    399                     for a in sorted(mod.added_aliases):
    400                         print("          + {0}".format(a))
    401                     for a in sorted(mod.removed_aliases):
    402                         print("          - {0}".format(a))
    403 
    404             print()
    405 
    406     if all_differences or args.sensitivity:
    407         if diff.added_sensitivities or diff.removed_sensitivities or diff.modified_sensitivities \
    408                 or args.sensitivity:
    409             print("Sensitivities ({0} Added, {1} Removed, {2} Modified)".format(
    410                 len(diff.added_sensitivities), len(diff.removed_sensitivities),
    411                 len(diff.modified_sensitivities)))
    412             if diff.added_sensitivities and not args.stats:
    413                 print("   Added Sensitivites: {0}".format(len(diff.added_sensitivities)))
    414                 for s in sorted(diff.added_sensitivities):
    415                     print("      + {0}".format(s))
    416             if diff.removed_sensitivities and not args.stats:
    417                 print("   Removed Sensitivities: {0}".format(len(diff.removed_sensitivities)))
    418                 for s in sorted(diff.removed_sensitivities):
    419                     print("      - {0}".format(s))
    420             if diff.modified_sensitivities and not args.stats:
    421                 print("   Modified Sensitivities: {0}".format(len(diff.modified_sensitivities)))
    422                 for name, mod in sorted(diff.modified_sensitivities.items()):
    423                     change = []
    424                     if mod.added_aliases:
    425                         change.append("{0} Added Aliases".format(len(mod.added_aliases)))
    426                     if mod.removed_aliases:
    427                         change.append("{0} Removed Aliases".format(len(mod.removed_aliases)))
    428 
    429                     print("      * {0} ({1})".format(name, ", ".join(change)))
    430                     print("          Aliases:")
    431                     for a in sorted(mod.added_aliases):
    432                         print("          + {0}".format(a))
    433                     for a in sorted(mod.removed_aliases):
    434                         print("          - {0}".format(a))
    435 
    436             print()
    437 
    438     if all_differences or args.level:
    439         if diff.added_levels or diff.removed_levels or \
    440                 diff.modified_levels or args.level:
    441             print("Levels ({0} Added, {1} Removed, {2} Modified)".format(
    442                 len(diff.added_levels), len(diff.removed_levels),
    443                 len(diff.modified_levels)))
    444             if diff.added_levels and not args.stats:
    445                 print("   Added Levels: {0}".format(len(diff.added_levels)))
    446                 for l in sorted(diff.added_levels):
    447                     print("      + {0}".format(l))
    448             if diff.removed_levels and not args.stats:
    449                 print("   Removed Levels: {0}".format(len(diff.removed_levels)))
    450                 for l in sorted(diff.removed_levels):
    451                     print("      - {0}".format(l))
    452             if diff.modified_levels and not args.stats:
    453                 print("   Modified Levels: {0}".format(len(diff.modified_levels)))
    454                 for level, added_categories, removed_categories, _ in sorted(diff.modified_levels,
    455                                                                              key=lambda x: x.level):
    456                     change = []
    457                     if added_categories:
    458                         change.append("{0} Added Categories".format(len(added_categories)))
    459                     if removed_categories:
    460                         change.append("{0} Removed Categories".format(len(removed_categories)))
    461 
    462                     print("      * {0} ({1})".format(level.sensitivity, ", ".join(change)))
    463                     for c in sorted(added_categories):
    464                         print("          + {0}".format(c))
    465                     for c in sorted(removed_categories):
    466                         print("          - {0}".format(c))
    467             print()
    468 
    469     if all_differences or args.allow:
    470         if diff.added_allows or diff.removed_allows or diff.modified_allows or args.allow:
    471             print("Allow Rules ({0} Added, {1} Removed, {2} Modified)".format(
    472                 len(diff.added_allows), len(diff.removed_allows), len(diff.modified_allows)))
    473 
    474             if diff.added_allows and not args.stats:
    475                 print("   Added Allow Rules: {0}".format(len(diff.added_allows)))
    476                 for r in sorted(diff.added_allows):
    477                     print("      + {0}".format(r))
    478 
    479             if diff.removed_allows and not args.stats:
    480                 print("   Removed Allow Rules: {0}".format(len(diff.removed_allows)))
    481                 for r in sorted(diff.removed_allows):
    482                     print("      - {0}".format(r))
    483 
    484             if diff.modified_allows and not args.stats:
    485                 print("   Modified Allow Rules: {0}".format(len(diff.modified_allows)))
    486 
    487                 for rule, added_perms, removed_perms, matched_perms in sorted(diff.modified_allows,
    488                                                                               key=lambda x: x.rule):
    489                     perms = " ".join(chain((p for p in matched_perms),
    490                                            ("+" + p for p in added_perms),
    491                                            ("-" + p for p in removed_perms)))
    492                     rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format(
    493                         rule, perms)
    494 
    495                     try:
    496                         rule_string += " [ {0} ]".format(rule.conditional)
    497                     except AttributeError:
    498                         pass
    499                     print("      * {0}".format(rule_string))
    500 
    501             print()
    502 
    503     if all_differences or args.allowxperm:
    504         if diff.added_allowxperms or diff.removed_allowxperms or diff.modified_allowxperms \
    505                 or args.allowxperm:
    506 
    507             print("Allowxperm Rules ({0} Added, {1} Removed, {2} Modified)".format(
    508                 len(diff.added_allowxperms), len(diff.removed_allowxperms),
    509                 len(diff.modified_allowxperms)))
    510 
    511             if diff.added_allowxperms and not args.stats:
    512                 print("   Added Allowxperm Rules: {0}".format(len(diff.added_allowxperms)))
    513                 for r in sorted(diff.added_allowxperms):
    514                     print("      + {0}".format(r))
    515 
    516             if diff.removed_allowxperms and not args.stats:
    517                 print("   Removed Allowxperm Rules: {0}".format(len(diff.removed_allowxperms)))
    518                 for r in sorted(diff.removed_allowxperms):
    519                     print("      - {0}".format(r))
    520 
    521             if diff.modified_allowxperms and not args.stats:
    522                 print("   Modified Allowxperm Rules: {0}".format(len(diff.modified_allowxperms)))
    523 
    524                 for rule, added_perms, removed_perms, matched_perms in sorted(
    525                         diff.modified_allowxperms, key=lambda x: x.rule):
    526 
    527                     # Process the string representation of the sets
    528                     # so hex representation and ranges are preserved.
    529                     # Check if the perm sets have contents, otherwise
    530                     # split on empty string will be an empty string.
    531                     # Add brackets to added and removed permissions
    532                     # in case there is a range of permissions.
    533                     perms = []
    534                     if matched_perms:
    535                         for p in str(matched_perms).split(" "):
    536                             perms.append(p)
    537                     if added_perms:
    538                         for p in str(added_perms).split(" "):
    539                             if '-' in p:
    540                                 perms.append("+[{0}]".format(p))
    541                             else:
    542                                 perms.append("+{0}".format(p))
    543                     if removed_perms:
    544                         for p in str(removed_perms).split(" "):
    545                             if '-' in p:
    546                                 perms.append("-[{0}]".format(p))
    547                             else:
    548                                 perms.append("-{0}".format(p))
    549 
    550                     rule_string = \
    551                         "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} {{ {1} }};". \
    552                         format(rule, perms)
    553 
    554                     print("      * {0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} "
    555                           "{{ {1} }};".format(rule, " ".join(perms)))
    556 
    557             print()
    558 
    559     if all_differences or args.neverallow:
    560         if diff.added_neverallows or diff.removed_neverallows or diff.modified_neverallows or \
    561                 args.neverallow:
    562             print("Neverallow Rules ({0} Added, {1} Removed, {2} Modified)".format(
    563                 len(diff.added_neverallows), len(diff.removed_neverallows),
    564                 len(diff.modified_neverallows)))
    565 
    566             if diff.added_neverallows and not args.stats:
    567                 print("   Added Neverallow Rules: {0}".format(len(diff.added_neverallows)))
    568                 for r in sorted(diff.added_neverallows):
    569                     print("      + {0}".format(r))
    570 
    571             if diff.removed_neverallows and not args.stats:
    572                 print("   Removed Neverallow Rules: {0}".format(len(diff.removed_neverallows)))
    573                 for r in sorted(diff.removed_neverallows):
    574                     print("      - {0}".format(r))
    575 
    576             if diff.modified_neverallows and not args.stats:
    577                 print("   Modified Neverallow Rules: {0}".format(len(diff.modified_neverallows)))
    578 
    579                 for rule, added_perms, removed_perms, matched_perms in sorted(
    580                         diff.modified_neverallows, key=lambda x: x.rule):
    581                     perms = " ".join(chain((p for p in matched_perms),
    582                                            ("+" + p for p in added_perms),
    583                                            ("-" + p for p in removed_perms)))
    584                     rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format(
    585                         rule, perms)
    586 
    587                     try:
    588                         rule_string += " [ {0} ]".format(rule.conditional)
    589                     except AttributeError:
    590                         pass
    591                     print("      * {0}".format(rule_string))
    592 
    593             print()
    594 
    595     if all_differences or args.neverallowxperm:
    596         if diff.added_neverallowxperms or diff.removed_neverallowxperms or \
    597                 diff.modified_neverallowxperms or args.neverallowxperm:
    598 
    599             print("Neverallowxperm Rules ({0} Added, {1} Removed, {2} Modified)".format(
    600                 len(diff.added_neverallowxperms), len(diff.removed_neverallowxperms),
    601                 len(diff.modified_neverallowxperms)))
    602 
    603             if diff.added_neverallowxperms and not args.stats:
    604                 print("   Added Neverallowxperm Rules: {0}".format(
    605                       len(diff.added_neverallowxperms)))
    606                 for r in sorted(diff.added_neverallowxperms):
    607                     print("      + {0}".format(r))
    608 
    609             if diff.removed_neverallowxperms and not args.stats:
    610                 print("   Removed Neverallowxperm Rules: {0}".format(
    611                       len(diff.removed_neverallowxperms)))
    612                 for r in sorted(diff.removed_neverallowxperms):
    613                     print("      - {0}".format(r))
    614 
    615             if diff.modified_neverallowxperms and not args.stats:
    616                 print("   Modified Neverallowxperm Rules: {0}".format(
    617                       len(diff.modified_neverallowxperms)))
    618 
    619                 for rule, added_perms, removed_perms, matched_perms in sorted(
    620                         diff.modified_neverallowxperms, key=lambda x: x.rule):
    621 
    622                     # Process the string representation of the sets
    623                     # so hex representation and ranges are preserved.
    624                     # Check if the perm sets have contents, otherwise
    625                     # split on empty string will be an empty string.
    626                     # Add brackets to added and removed permissions
    627                     # in case there is a range of permissions.
    628                     perms = []
    629                     if matched_perms:
    630                         for p in str(matched_perms).split(" "):
    631                             perms.append(p)
    632                     if added_perms:
    633                         for p in str(added_perms).split(" "):
    634                             if '-' in p:
    635                                 perms.append("+[{0}]".format(p))
    636                             else:
    637                                 perms.append("+{0}".format(p))
    638                     if removed_perms:
    639                         for p in str(removed_perms).split(" "):
    640                             if '-' in p:
    641                                 perms.append("-[{0}]".format(p))
    642                             else:
    643                                 perms.append("-{0}".format(p))
    644 
    645                     rule_string = \
    646                         "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} {{ {1} }};". \
    647                         format(rule, perms)
    648 
    649                     print("      * {0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} "
    650                           "{{ {1} }};".format(rule, " ".join(perms)))
    651 
    652             print()
    653 
    654     if all_differences or args.auditallow:
    655         if diff.added_auditallows or diff.removed_auditallows or diff.modified_auditallows or \
    656                 args.auditallow:
    657             print("Auditallow Rules ({0} Added, {1} Removed, {2} Modified)".format(
    658                 len(diff.added_auditallows), len(diff.removed_auditallows),
    659                 len(diff.modified_auditallows)))
    660 
    661             if diff.added_auditallows and not args.stats:
    662                 print("   Added Auditallow Rules: {0}".format(len(diff.added_auditallows)))
    663                 for r in sorted(diff.added_auditallows):
    664                     print("      + {0}".format(r))
    665 
    666             if diff.removed_auditallows and not args.stats:
    667                 print("   Removed Auditallow Rules: {0}".format(len(diff.removed_auditallows)))
    668                 for r in sorted(diff.removed_auditallows):
    669                     print("      - {0}".format(r))
    670 
    671             if diff.modified_auditallows and not args.stats:
    672                 print("   Modified Auditallow Rules: {0}".format(len(diff.modified_auditallows)))
    673 
    674                 for rule, added_perms, removed_perms, matched_perms in sorted(
    675                         diff.modified_auditallows, key=lambda x: x.rule):
    676                     perms = " ".join(chain((p for p in matched_perms),
    677                                            ("+" + p for p in added_perms),
    678                                            ("-" + p for p in removed_perms)))
    679                     rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format(
    680                         rule, perms)
    681 
    682                     try:
    683                         rule_string += " [ {0} ]".format(rule.conditional)
    684                     except AttributeError:
    685                         pass
    686                     print("      * {0}".format(rule_string))
    687 
    688             print()
    689 
    690     if all_differences or args.auditallowxperm:
    691         if diff.added_auditallowxperms or diff.removed_auditallowxperms or \
    692                 diff.modified_auditallowxperms or args.auditallowxperm:
    693 
    694             print("Auditallowxperm Rules ({0} Added, {1} Removed, {2} Modified)".format(
    695                 len(diff.added_auditallowxperms), len(diff.removed_auditallowxperms),
    696                 len(diff.modified_auditallowxperms)))
    697 
    698             if diff.added_auditallowxperms and not args.stats:
    699                 print("   Added Auditallowxperm Rules: {0}".format(
    700                       len(diff.added_auditallowxperms)))
    701                 for r in sorted(diff.added_auditallowxperms):
    702                     print("      + {0}".format(r))
    703 
    704             if diff.removed_auditallowxperms and not args.stats:
    705                 print("   Removed Auditallowxperm Rules: {0}".format(
    706                       len(diff.removed_auditallowxperms)))
    707                 for r in sorted(diff.removed_auditallowxperms):
    708                     print("      - {0}".format(r))
    709 
    710             if diff.modified_auditallowxperms and not args.stats:
    711                 print("   Modified Auditallowxperm Rules: {0}".format(
    712                       len(diff.modified_auditallowxperms)))
    713 
    714                 for rule, added_perms, removed_perms, matched_perms in sorted(
    715                         diff.modified_auditallowxperms, key=lambda x: x.rule):
    716 
    717                     # Process the string representation of the sets
    718                     # so hex representation and ranges are preserved.
    719                     # Check if the perm sets have contents, otherwise
    720                     # split on empty string will be an empty string.
    721                     # Add brackets to added and removed permissions
    722                     # in case there is a range of permissions.
    723                     perms = []
    724                     if matched_perms:
    725                         for p in str(matched_perms).split(" "):
    726                             perms.append(p)
    727                     if added_perms:
    728                         for p in str(added_perms).split(" "):
    729                             if '-' in p:
    730                                 perms.append("+[{0}]".format(p))
    731                             else:
    732                                 perms.append("+{0}".format(p))
    733                     if removed_perms:
    734                         for p in str(removed_perms).split(" "):
    735                             if '-' in p:
    736                                 perms.append("-[{0}]".format(p))
    737                             else:
    738                                 perms.append("-{0}".format(p))
    739 
    740                     rule_string = \
    741                         "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} {{ {1} }};". \
    742                         format(rule, perms)
    743 
    744                     print("      * {0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} "
    745                           "{{ {1} }};".format(rule, " ".join(perms)))
    746 
    747             print()
    748 
    749     if all_differences or args.dontaudit:
    750         if diff.added_dontaudits or diff.removed_dontaudits or diff.modified_dontaudits or \
    751                 args.dontaudit:
    752             print("Dontaudit Rules ({0} Added, {1} Removed, {2} Modified)".format(
    753                 len(diff.added_dontaudits), len(diff.removed_dontaudits),
    754                 len(diff.modified_dontaudits)))
    755 
    756             if diff.added_dontaudits and not args.stats:
    757                 print("   Added Dontaudit Rules: {0}".format(len(diff.added_dontaudits)))
    758                 for r in sorted(diff.added_dontaudits):
    759                     print("      + {0}".format(r))
    760 
    761             if diff.removed_dontaudits and not args.stats:
    762                 print("   Removed Dontaudit Rules: {0}".format(len(diff.removed_dontaudits)))
    763                 for r in sorted(diff.removed_dontaudits):
    764                     print("      - {0}".format(r))
    765 
    766             if diff.modified_dontaudits and not args.stats:
    767                 print("   Modified Dontaudit Rules: {0}".format(len(diff.modified_dontaudits)))
    768 
    769                 for rule, added_perms, removed_perms, matched_perms in sorted(
    770                         diff.modified_dontaudits, key=lambda x: x.rule):
    771                     perms = " ".join(chain((p for p in matched_perms),
    772                                            ("+" + p for p in added_perms),
    773                                            ("-" + p for p in removed_perms)))
    774                     rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format(
    775                         rule, perms)
    776 
    777                     try:
    778                         rule_string += " [ {0} ]".format(rule.conditional)
    779                     except AttributeError:
    780                         pass
    781                     print("      * {0}".format(rule_string))
    782 
    783             print()
    784 
    785     if all_differences or args.dontauditxperm:
    786         if diff.added_dontauditxperms or diff.removed_dontauditxperms or \
    787                 diff.modified_dontauditxperms or args.dontauditxperm:
    788 
    789             print("Dontauditxperm Rules ({0} Added, {1} Removed, {2} Modified)".format(
    790                 len(diff.added_dontauditxperms), len(diff.removed_dontauditxperms),
    791                 len(diff.modified_dontauditxperms)))
    792 
    793             if diff.added_dontauditxperms and not args.stats:
    794                 print("   Added Dontauditxperm Rules: {0}".format(
    795                       len(diff.added_dontauditxperms)))
    796                 for r in sorted(diff.added_dontauditxperms):
    797                     print("      + {0}".format(r))
    798 
    799             if diff.removed_dontauditxperms and not args.stats:
    800                 print("   Removed Dontauditxperm Rules: {0}".format(
    801                       len(diff.removed_dontauditxperms)))
    802                 for r in sorted(diff.removed_dontauditxperms):
    803                     print("      - {0}".format(r))
    804 
    805             if diff.modified_dontauditxperms and not args.stats:
    806                 print("   Modified Dontauditxperm Rules: {0}".format(
    807                       len(diff.modified_dontauditxperms)))
    808 
    809                 for rule, added_perms, removed_perms, matched_perms in sorted(
    810                         diff.modified_dontauditxperms, key=lambda x: x.rule):
    811 
    812                     # Process the string representation of the sets
    813                     # so hex representation and ranges are preserved.
    814                     # Check if the perm sets have contents, otherwise
    815                     # split on empty string will be an empty string.
    816                     # Add brackets to added and removed permissions
    817                     # in case there is a range of permissions.
    818                     perms = []
    819                     if matched_perms:
    820                         for p in str(matched_perms).split(" "):
    821                             perms.append(p)
    822                     if added_perms:
    823                         for p in str(added_perms).split(" "):
    824                             if '-' in p:
    825                                 perms.append("+[{0}]".format(p))
    826                             else:
    827                                 perms.append("+{0}".format(p))
    828                     if removed_perms:
    829                         for p in str(removed_perms).split(" "):
    830                             if '-' in p:
    831                                 perms.append("-[{0}]".format(p))
    832                             else:
    833                                 perms.append("-{0}".format(p))
    834 
    835                     rule_string = \
    836                         "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} {{ {1} }};". \
    837                         format(rule, perms)
    838 
    839                     print("      * {0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} "
    840                           "{{ {1} }};".format(rule, " ".join(perms)))
    841 
    842             print()
    843 
    844     if all_differences or args.type_trans:
    845         if diff.added_type_transitions or diff.removed_type_transitions or \
    846                 diff.modified_type_transitions or args.type_trans:
    847             print("Type_transition Rules ({0} Added, {1} Removed, {2} Modified)".format(
    848                 len(diff.added_type_transitions), len(diff.removed_type_transitions),
    849                 len(diff.modified_type_transitions)))
    850 
    851             if diff.added_type_transitions and not args.stats:
    852                 print("   Added Type_transition Rules: {0}".format(
    853                     len(diff.added_type_transitions)))
    854                 for r in sorted(diff.added_type_transitions):
    855                     print("      + {0}".format(r))
    856 
    857             if diff.removed_type_transitions and not args.stats:
    858                 print("   Removed Type_transition Rules: {0}".format(
    859                     len(diff.removed_type_transitions)))
    860                 for r in sorted(diff.removed_type_transitions):
    861                     print("      - {0}".format(r))
    862 
    863             if diff.modified_type_transitions and not args.stats:
    864                 print("   Modified Type_transition Rules: {0}".format(
    865                     len(diff.modified_type_transitions)))
    866 
    867                 for rule, added_default, removed_default in sorted(diff.modified_type_transitions,
    868                                                                    key=lambda x: x.rule):
    869                     rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format(
    870                         rule, added_default, removed_default)
    871 
    872                     try:
    873                         rule_string += " {0}".format(rule.filename)
    874                     except AttributeError:
    875                         pass
    876 
    877                     rule_string += ";"
    878 
    879                     try:
    880                         rule_string += " [ {0} ]".format(rule.conditional)
    881                     except AttributeError:
    882                         pass
    883 
    884                     print("      * {0}".format(rule_string))
    885 
    886             print()
    887 
    888     if all_differences or args.type_change:
    889         if diff.added_type_changes or diff.removed_type_changes or \
    890                 diff.modified_type_changes or args.type_change:
    891             print("Type_change Rules ({0} Added, {1} Removed, {2} Modified)".format(
    892                 len(diff.added_type_changes), len(diff.removed_type_changes),
    893                 len(diff.modified_type_changes)))
    894 
    895             if diff.added_type_changes and not args.stats:
    896                 print("   Added Type_change Rules: {0}".format(len(diff.added_type_changes)))
    897                 for r in sorted(diff.added_type_changes):
    898                     print("      + {0}".format(r))
    899 
    900             if diff.removed_type_changes and not args.stats:
    901                 print("   Removed Type_change Rules: {0}".format(len(diff.removed_type_changes)))
    902                 for r in sorted(diff.removed_type_changes):
    903                     print("      - {0}".format(r))
    904 
    905             if diff.modified_type_changes and not args.stats:
    906                 print("   Modified Type_change Rules: {0}".format(len(diff.modified_type_changes)))
    907 
    908                 for rule, added_default, removed_default in sorted(diff.modified_type_changes,
    909                                                                    key=lambda x: x.rule):
    910                     rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format(
    911                         rule, added_default, removed_default)
    912 
    913                     try:
    914                         rule_string += " {0}".format(rule.filename)
    915                     except AttributeError:
    916                         pass
    917 
    918                     rule_string += ";"
    919 
    920                     try:
    921                         rule_string += " [ {0} ]".format(rule.conditional)
    922                     except AttributeError:
    923                         pass
    924 
    925                     print("      * {0}".format(rule_string))
    926 
    927             print()
    928 
    929     if all_differences or args.type_member:
    930         if diff.added_type_members or diff.removed_type_members or \
    931                 diff.modified_type_members or args.type_member:
    932             print("Type_member Rules ({0} Added, {1} Removed, {2} Modified)".format(
    933                 len(diff.added_type_members), len(diff.removed_type_members),
    934                 len(diff.modified_type_members)))
    935 
    936             if diff.added_type_members and not args.stats:
    937                 print("   Added Type_member Rules: {0}".format(len(diff.added_type_members)))
    938                 for r in sorted(diff.added_type_members):
    939                     print("      + {0}".format(r))
    940 
    941             if diff.removed_type_members and not args.stats:
    942                 print("   Removed Type_member Rules: {0}".format(len(diff.removed_type_members)))
    943                 for r in sorted(diff.removed_type_members):
    944                     print("      - {0}".format(r))
    945 
    946             if diff.modified_type_members and not args.stats:
    947                 print("   Modified Type_member Rules: {0}".format(len(diff.modified_type_members)))
    948 
    949                 for rule, added_default, removed_default in sorted(diff.modified_type_members,
    950                                                                    key=lambda x: x.rule):
    951                     rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format(
    952                         rule, added_default, removed_default)
    953 
    954                     try:
    955                         rule_string += " {0}".format(rule.filename)
    956                     except AttributeError:
    957                         pass
    958 
    959                     rule_string += ";"
    960 
    961                     try:
    962                         rule_string += " [ {0} ]".format(rule.conditional)
    963                     except AttributeError:
    964                         pass
    965 
    966                     print("      * {0}".format(rule_string))
    967 
    968             print()
    969 
    970     if all_differences or args.role_allow:
    971         if diff.added_role_allows or diff.removed_role_allows or args.role_allow:
    972             print("Role allow Rules ({0} Added, {1} Removed)".format(
    973                 len(diff.added_role_allows), len(diff.removed_role_allows)))
    974 
    975             if diff.added_role_allows and not args.stats:
    976                 print("   Added Role Allow Rules: {0}".format(
    977                     len(diff.added_role_allows)))
    978                 for r in sorted(diff.added_role_allows):
    979                     print("      + {0}".format(r))
    980 
    981             if diff.removed_role_allows and not args.stats:
    982                 print("   Removed Role Allow Rules: {0}".format(
    983                     len(diff.removed_role_allows)))
    984                 for r in sorted(diff.removed_role_allows):
    985                     print("      - {0}".format(r))
    986 
    987             print()
    988 
    989     if all_differences or args.role_trans:
    990         if diff.added_role_transitions or diff.removed_role_transitions or \
    991                 diff.modified_role_transitions or args.role_trans:
    992             print("Role_transition Rules ({0} Added, {1} Removed, {2} Modified)".format(
    993                 len(diff.added_role_transitions), len(diff.removed_role_transitions),
    994                 len(diff.modified_role_transitions)))
    995 
    996             if diff.added_role_transitions and not args.stats:
    997                 print("   Added Role_transition Rules: {0}".format(
    998                     len(diff.added_role_transitions)))
    999                 for r in sorted(diff.added_role_transitions):
   1000                     print("      + {0}".format(r))
   1001 
   1002             if diff.removed_role_transitions and not args.stats:
   1003                 print("   Removed Role_transition Rules: {0}".format(
   1004                     len(diff.removed_role_transitions)))
   1005                 for r in sorted(diff.removed_role_transitions):
   1006                     print("      - {0}".format(r))
   1007 
   1008             if diff.modified_role_transitions and not args.stats:
   1009                 print("   Modified Role_transition Rules: {0}".format(
   1010                     len(diff.modified_role_transitions)))
   1011 
   1012                 for rule, added_default, removed_default in sorted(diff.modified_role_transitions,
   1013                                                                    key=lambda x: x.rule):
   1014                     rule_string = \
   1015                         "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format(
   1016                             rule, added_default, removed_default)
   1017 
   1018                     print("      * {0}".format(rule_string))
   1019 
   1020             print()
   1021 
   1022     if all_differences or args.range_trans:
   1023         if diff.added_range_transitions or diff.removed_range_transitions or \
   1024                 diff.modified_range_transitions or args.range_trans:
   1025             print("Range_transition Rules ({0} Added, {1} Removed, {2} Modified)".format(
   1026                 len(diff.added_range_transitions), len(diff.removed_range_transitions),
   1027                 len(diff.modified_range_transitions)))
   1028 
   1029             if diff.added_range_transitions and not args.stats:
   1030                 print("   Added Range_transition Rules: {0}".format(
   1031                     len(diff.added_range_transitions)))
   1032                 for r in sorted(diff.added_range_transitions):
   1033                     print("      + {0}".format(r))
   1034 
   1035             if diff.removed_range_transitions and not args.stats:
   1036                 print("   Removed Range_transition Rules: {0}".format(
   1037                     len(diff.removed_range_transitions)))
   1038                 for r in sorted(diff.removed_range_transitions):
   1039                     print("      - {0}".format(r))
   1040 
   1041             if diff.modified_range_transitions and not args.stats:
   1042                 print("   Modified Range_transition Rules: {0}".format(
   1043                     len(diff.modified_range_transitions)))
   1044 
   1045                 for rule, added_default, removed_default in sorted(diff.modified_range_transitions,
   1046                                                                    key=lambda x: x.rule):
   1047                     # added brackets around range change for clarity since ranges
   1048                     # can have '-' and spaces.
   1049                     rule_string = \
   1050                         "{0.ruletype} {0.source} {0.target}:{0.tclass} +[{1}] -[{2}]".format(
   1051                             rule, added_default, removed_default)
   1052 
   1053                     print("      * {0}".format(rule_string))
   1054 
   1055             print()
   1056 
   1057     if all_differences or args.constrain:
   1058         if diff.added_constrains or diff.removed_constrains or args.constrain:
   1059             print("Constraints ({0} Added, {1} Removed)".format(
   1060                 len(diff.added_constrains), len(diff.removed_constrains)))
   1061 
   1062             if diff.added_constrains and not args.stats:
   1063                 print("   Added Constraints: {0}".format(
   1064                     len(diff.added_constrains)))
   1065                 for r in sorted(diff.added_constrains):
   1066                     print("      + {0}".format(r))
   1067 
   1068             if diff.removed_constrains and not args.stats:
   1069                 print("   Removed Constraints: {0}".format(
   1070                     len(diff.removed_constrains)))
   1071                 for r in sorted(diff.removed_constrains):
   1072                     print("      - {0}".format(r))
   1073 
   1074             print()
   1075 
   1076     if all_differences or args.mlsconstrain:
   1077         if diff.added_mlsconstrains or diff.removed_mlsconstrains or args.mlsconstrain:
   1078             print("MLS Constraints ({0} Added, {1} Removed)".format(
   1079                 len(diff.added_mlsconstrains), len(diff.removed_mlsconstrains)))
   1080 
   1081             if diff.added_mlsconstrains and not args.stats:
   1082                 print("   Added MLS Constraints: {0}".format(
   1083                     len(diff.added_mlsconstrains)))
   1084                 for r in sorted(diff.added_mlsconstrains):
   1085                     print("      + {0}".format(r))
   1086 
   1087             if diff.removed_mlsconstrains and not args.stats:
   1088                 print("   Removed MLS Constraints: {0}".format(
   1089                     len(diff.removed_mlsconstrains)))
   1090                 for r in sorted(diff.removed_mlsconstrains):
   1091                     print("      - {0}".format(r))
   1092 
   1093             print()
   1094 
   1095     if all_differences or args.validatetrans:
   1096         if diff.added_validatetrans or diff.removed_validatetrans or args.validatetrans:
   1097             print("Validatetrans ({0} Added, {1} Removed)".format(
   1098                 len(diff.added_validatetrans), len(diff.removed_validatetrans)))
   1099 
   1100             if diff.added_validatetrans and not args.stats:
   1101                 print("   Added Validatetrans: {0}".format(
   1102                     len(diff.added_validatetrans)))
   1103                 for r in sorted(diff.added_validatetrans):
   1104                     print("      + {0}".format(r))
   1105 
   1106             if diff.removed_validatetrans and not args.stats:
   1107                 print("   Removed Validatetrans: {0}".format(
   1108                     len(diff.removed_validatetrans)))
   1109                 for r in sorted(diff.removed_validatetrans):
   1110                     print("      - {0}".format(r))
   1111 
   1112             print()
   1113 
   1114     if all_differences or args.mlsvalidatetrans:
   1115         if diff.added_mlsvalidatetrans or diff.removed_mlsvalidatetrans or args.mlsvalidatetrans:
   1116             print("MLS Validatetrans ({0} Added, {1} Removed)".format(
   1117                 len(diff.added_mlsvalidatetrans), len(diff.removed_mlsvalidatetrans)))
   1118 
   1119             if diff.added_mlsvalidatetrans and not args.stats:
   1120                 print("   Added MLS Validatetrans: {0}".format(
   1121                     len(diff.added_mlsvalidatetrans)))
   1122                 for r in sorted(diff.added_mlsvalidatetrans):
   1123                     print("      + {0}".format(r))
   1124 
   1125             if diff.removed_mlsvalidatetrans and not args.stats:
   1126                 print("   Removed MLS Validatetrans: {0}".format(
   1127                     len(diff.removed_mlsvalidatetrans)))
   1128                 for r in sorted(diff.removed_mlsvalidatetrans):
   1129                     print("      - {0}".format(r))
   1130 
   1131             print()
   1132 
   1133     if all_differences or args.initialsid:
   1134         if diff.added_initialsids or diff.removed_initialsids or diff.modified_initialsids \
   1135                 or args.initialsid:
   1136             print("Initial SIDs ({0} Added, {1} Removed, {2} Modified)".format(
   1137                 len(diff.added_initialsids), len(diff.removed_initialsids),
   1138                 len(diff.modified_initialsids)))
   1139             if diff.added_initialsids and not args.stats:
   1140                 print("   Added Initial SIDs: {0}".format(len(diff.added_initialsids)))
   1141                 for s in sorted(diff.added_initialsids):
   1142                     print("      + {0}".format(s.statement()))
   1143             if diff.removed_initialsids and not args.stats:
   1144                 print("   Removed Initial SIDs: {0}".format(len(diff.removed_initialsids)))
   1145                 for s in sorted(diff.removed_initialsids):
   1146                     print("      - {0}".format(s.statement()))
   1147             if diff.modified_initialsids and not args.stats:
   1148                 print("   Modified Initial SIDs: {0}".format(len(diff.modified_initialsids)))
   1149                 for name, mod in sorted(diff.modified_initialsids.items()):
   1150                     print("      * {0} +[{1.added_context}] -[{1.removed_context}];".format(
   1151                           name, mod))
   1152 
   1153             print()
   1154 
   1155     if all_differences or args.fs_use:
   1156         if diff.added_fs_uses or diff.removed_fs_uses or diff.modified_fs_uses \
   1157                 or args.fs_use:
   1158             print("Fs_use ({0} Added, {1} Removed, {2} Modified)".format(
   1159                 len(diff.added_fs_uses), len(diff.removed_fs_uses),
   1160                 len(diff.modified_fs_uses)))
   1161             if diff.added_fs_uses and not args.stats:
   1162                 print("   Added Fs_use: {0}".format(len(diff.added_fs_uses)))
   1163                 for s in sorted(diff.added_fs_uses):
   1164                     print("      + {0}".format(s))
   1165             if diff.removed_fs_uses and not args.stats:
   1166                 print("   Removed Fs_use: {0}".format(len(diff.removed_fs_uses)))
   1167                 for s in sorted(diff.removed_fs_uses):
   1168                     print("      - {0}".format(s))
   1169             if diff.modified_fs_uses and not args.stats:
   1170                 print("   Modified Fs_use: {0}".format(len(diff.modified_fs_uses)))
   1171                 for entry in sorted(diff.modified_fs_uses, key=lambda x: x.rule):
   1172                     print("      * {0.ruletype} {0.fs} +[{1}] -[{2}];".format(
   1173                           entry.rule, entry.added_context, entry.removed_context))
   1174 
   1175             print()
   1176 
   1177     if all_differences or args.genfscon:
   1178         if diff.added_genfscons or diff.removed_genfscons or diff.modified_genfscons \
   1179                 or args.genfscon:
   1180             print("Genfscons ({0} Added, {1} Removed, {2} Modified)".format(
   1181                 len(diff.added_genfscons), len(diff.removed_genfscons),
   1182                 len(diff.modified_genfscons)))
   1183             if diff.added_genfscons and not args.stats:
   1184                 print("   Added Genfscons: {0}".format(len(diff.added_genfscons)))
   1185                 for s in sorted(diff.added_genfscons):
   1186                     print("      + {0}".format(s))
   1187             if diff.removed_genfscons and not args.stats:
   1188                 print("   Removed Genfscons: {0}".format(len(diff.removed_genfscons)))
   1189                 for s in sorted(diff.removed_genfscons):
   1190                     print("      - {0}".format(s))
   1191             if diff.modified_genfscons and not args.stats:
   1192                 print("   Modified Genfscons: {0}".format(len(diff.modified_genfscons)))
   1193                 for entry in sorted(diff.modified_genfscons, key=lambda x: x.rule):
   1194                     print("      * genfscon {0.fs} {0.path} {0.filetype} +[{1}] -[{2}];".format(
   1195                           entry.rule, entry.added_context, entry.removed_context))
   1196 
   1197             print()
   1198 
   1199     if all_differences or args.netifcon:
   1200         if diff.added_netifcons or diff.removed_netifcons or \
   1201                 diff.modified_netifcons or args.netifcon:
   1202             print("Netifcons ({0} Added, {1} Removed, {2} Modified)".format(
   1203                 len(diff.added_netifcons), len(diff.removed_netifcons),
   1204                 len(diff.modified_netifcons)))
   1205             if diff.added_netifcons and not args.stats:
   1206                 print("   Added Netifcons: {0}".format(len(diff.added_netifcons)))
   1207                 for n in sorted(diff.added_netifcons):
   1208                     print("      + {0}".format(n))
   1209             if diff.removed_netifcons and not args.stats:
   1210                 print("   Removed Netifcons: {0}".format(len(diff.removed_netifcons)))
   1211                 for n in sorted(diff.removed_netifcons):
   1212                     print("      - {0}".format(n))
   1213             if diff.modified_netifcons and not args.stats:
   1214                 print("   Modified Netifcons: {0}".format(len(diff.modified_netifcons)))
   1215                 for entry in sorted(diff.modified_netifcons, key=lambda x: x.rule):
   1216                     # This output is different than other statements because
   1217                     # it becomes difficult to read if this was condensed
   1218                     # into a single line, especially if both contexts
   1219                     # are modified.
   1220                     change = []
   1221                     if entry.removed_context:
   1222                         change.append("Modified Context")
   1223                     if entry.removed_packet:
   1224                         change.append("Modified Packet Context")
   1225 
   1226                     print("      * {0.netif} ({1})".format(entry.rule, ", ".join(change)))
   1227 
   1228                     if entry.removed_context:
   1229                         print("          Context:")
   1230                         print("             + {0}".format(entry.added_context))
   1231                         print("             - {0}".format(entry.removed_context))
   1232                     if entry.removed_packet:
   1233                         print("          Packet Context:")
   1234                         print("             + {0}".format(entry.added_packet))
   1235                         print("             - {0}".format(entry.removed_packet))
   1236 
   1237             print()
   1238 
   1239     if all_differences or args.nodecon:
   1240         if diff.added_nodecons or diff.removed_nodecons or diff.modified_nodecons \
   1241                 or args.nodecon:
   1242             print("Nodecons ({0} Added, {1} Removed, {2} Modified)".format(
   1243                 len(diff.added_nodecons), len(diff.removed_nodecons),
   1244                 len(diff.modified_nodecons)))
   1245             if diff.added_nodecons and not args.stats:
   1246                 print("   Added Nodecons: {0}".format(len(diff.added_nodecons)))
   1247                 for n in sorted(diff.added_nodecons):
   1248                     print("      + {0}".format(n))
   1249             if diff.removed_nodecons and not args.stats:
   1250                 print("   Removed Nodecons: {0}".format(len(diff.removed_nodecons)))
   1251                 for n in sorted(diff.removed_nodecons):
   1252                     print("      - {0}".format(n))
   1253             if diff.modified_nodecons and not args.stats:
   1254                 print("   Modified Nodecons: {0}".format(len(diff.modified_nodecons)))
   1255                 for con, added_context, removed_context in sorted(diff.modified_nodecons,
   1256                                                                   key=lambda x: x.rule):
   1257                     print("      * nodecon {0.address} {0.netmask} +[{1}] -[{2}];".format(
   1258                           con, added_context, removed_context))
   1259 
   1260             print()
   1261 
   1262     if all_differences or args.portcon:
   1263         if diff.added_portcons or diff.removed_portcons or diff.modified_portcons \
   1264                 or args.portcon:
   1265             print("Portcons ({0} Added, {1} Removed, {2} Modified)".format(
   1266                 len(diff.added_portcons), len(diff.removed_portcons),
   1267                 len(diff.modified_portcons)))
   1268             if diff.added_portcons and not args.stats:
   1269                 print("   Added Portcons: {0}".format(len(diff.added_portcons)))
   1270                 for n in sorted(diff.added_portcons):
   1271                     print("      + {0}".format(n))
   1272             if diff.removed_portcons and not args.stats:
   1273                 print("   Removed Portcons: {0}".format(len(diff.removed_portcons)))
   1274                 for n in sorted(diff.removed_portcons):
   1275                     print("      - {0}".format(n))
   1276             if diff.modified_portcons and not args.stats:
   1277                 print("   Modified Portcons: {0}".format(len(diff.modified_portcons)))
   1278                 for con, added_context, removed_context in sorted(diff.modified_portcons,
   1279                                                                   key=lambda x: x.rule):
   1280                     low, high = con.ports
   1281                     if low == high:
   1282                         print("      * portcon {0.protocol} {1} +[{2}] -[{3}];".format(
   1283                               con, low, added_context, removed_context))
   1284                     else:
   1285                         print("      * portcon {0.protocol} {1}-{2} +[{3}] -[{4}];".format(
   1286                               con, low, high, added_context, removed_context))
   1287 
   1288             print()
   1289 
   1290     if all_differences or args.polcap:
   1291         if diff.added_polcaps or diff.removed_polcaps or args.polcap:
   1292             print("Policy Capabilities ({0} Added, {1} Removed)".format(
   1293                 len(diff.added_polcaps), len(diff.removed_polcaps)))
   1294             if diff.added_polcaps and not args.stats:
   1295                 print("   Added Policy Capabilities: {0}".format(len(diff.added_polcaps)))
   1296                 for n in sorted(diff.added_polcaps):
   1297                     print("      + {0}".format(n))
   1298             if diff.removed_polcaps and not args.stats:
   1299                 print("   Removed Policy Capabilities: {0}".format(len(diff.removed_polcaps)))
   1300                 for n in sorted(diff.removed_polcaps):
   1301                     print("      - {0}".format(n))
   1302 
   1303             print()
   1304 
   1305     if all_differences or args.default:
   1306         if diff.added_defaults or diff.removed_defaults or args.default:
   1307             print("Defaults ({0} Added, {1} Removed, {2} Modified)".format(
   1308                 len(diff.added_defaults), len(diff.removed_defaults), len(diff.modified_defaults)))
   1309             if diff.added_defaults and not args.stats:
   1310                 print("   Added Defaults: {0}".format(len(diff.added_defaults)))
   1311                 for d in sorted(diff.added_defaults):
   1312                     print("      + {0}".format(d))
   1313             if diff.removed_defaults and not args.stats:
   1314                 print("   Removed Defaults: {0}".format(len(diff.removed_defaults)))
   1315                 for d in sorted(diff.removed_defaults):
   1316                     print("      - {0}".format(d))
   1317             if diff.modified_defaults and not args.stats:
   1318                 print("   Modified Defaults: {0}".format(len(diff.modified_defaults)))
   1319                 for default, added_default, removed_default, added_range, removed_range in sorted(
   1320                         diff.modified_defaults, key=lambda x: x.rule):
   1321                     line = "      * {0.ruletype} {0.tclass} ".format(default)
   1322                     if removed_default:
   1323                         line += "+{0} -{1}".format(added_default, removed_default)
   1324                     else:
   1325                         line += default.default
   1326 
   1327                     if removed_range:
   1328                         line += " +{0} -{1};".format(added_range, removed_range)
   1329                     else:
   1330                         try:
   1331                             line += " {0};".format(default.default_range)
   1332                         except AttributeError:
   1333                             line += ";"
   1334                     print(line)
   1335 
   1336             print()
   1337 
   1338     if all_differences or args.typebounds:
   1339         if diff.added_typebounds or diff.removed_typebounds or args.typebounds:
   1340             print("Typebounds ({0} Added, {1} Removed, {2} Modified)".format(
   1341                   len(diff.added_typebounds), len(diff.removed_typebounds),
   1342                   len(diff.modified_typebounds)))
   1343             if diff.added_typebounds and not args.stats:
   1344                 print("   Added Typebounds: {0}".format(len(diff.added_typebounds)))
   1345                 for d in sorted(diff.added_typebounds):
   1346                     print("      + {0}".format(d))
   1347             if diff.removed_typebounds and not args.stats:
   1348                 print("   Removed Typebounds: {0}".format(len(diff.removed_typebounds)))
   1349                 for d in sorted(diff.removed_typebounds):
   1350                     print("      - {0}".format(d))
   1351             if diff.modified_typebounds and not args.stats:
   1352                 print("   Modified Typebounds: {0}".format(len(diff.modified_typebounds)))
   1353                 for bound, added_bound, removed_bound in sorted(
   1354                         diff.modified_typebounds, key=lambda x: x.rule):
   1355                     print("      * {0.ruletype} +{1} -{2} {0.child};".format(
   1356                           bound, added_bound, removed_bound))
   1357 
   1358             print()
   1359 
   1360 except Exception as err:
   1361     if args.debug:
   1362         logging.exception(str(err))
   1363     else:
   1364         print(err)
   1365 
   1366     sys.exit(1)
   1367