• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
20from __future__ import print_function
21import setools
22import argparse
23import sys
24import logging
25from itertools import chain
26
27parser = argparse.ArgumentParser(
28    description="SELinux policy semantic difference tool.",
29    epilog="If no differences are selected, all differences will be printed.")
30parser.add_argument("POLICY1", help="Path to the first SELinux policy to diff.", nargs=1)
31parser.add_argument("POLICY2", help="Path to the second SELinux policy to diff.", nargs=1)
32parser.add_argument("--version", action="version", version=setools.__version__)
33parser.add_argument("--stats", action="store_true", help="Display only statistics.")
34parser.add_argument("-v", "--verbose", action="store_true",
35                    help="Print extra informational messages")
36parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.")
37
38comp = parser.add_argument_group("component differences")
39comp.add_argument("--common", action="store_true", help="Print common differences")
40comp.add_argument("-c", "--class", action="store_true", help="Print class differences",
41                  dest="class_")
42comp.add_argument("-t", "--type", action="store_true", help="Print type differences",
43                  dest="type_")
44comp.add_argument("-a", "--attribute", action="store_true", help="Print type attribute differences")
45comp.add_argument("-r", "--role", action="store_true", help="Print role differences")
46comp.add_argument("-u", "--user", action="store_true", help="Print user differences")
47comp.add_argument("-b", "--bool", action="store_true", help="Print Boolean differences",
48                  dest="bool_")
49comp.add_argument("--sensitivity", action="store_true", help="Print MLS sensitivity differences")
50comp.add_argument("--category", action="store_true", help="Print MLS category differences")
51comp.add_argument("--level", action="store_true", help="Print MLS level definition differences")
52
53terule = parser.add_argument_group("type enforcement rule differences")
54terule.add_argument("-A", action="store_true", help="Print allow and allowxperm rule differences")
55terule.add_argument("--allow", action="store_true", help="Print allow rule differences")
56terule.add_argument("--neverallow", action="store_true", help="Print neverallow rule differences")
57terule.add_argument("--auditallow", action="store_true", help="Print auditallow rule differences")
58terule.add_argument("--dontaudit", action="store_true", help="Print dontaudit rule differences")
59terule.add_argument("--allowxperm", action="store_true", help="Print allowxperm rule differences")
60terule.add_argument("--neverallowxperm", action="store_true",
61                    help="Print neverallowxperm rule differences")
62terule.add_argument("--auditallowxperm", action="store_true",
63                    help="Print auditallowxperm rule differences")
64terule.add_argument("--dontauditxperm", action="store_true",
65                    help="Print dontauditxperm rule differences")
66terule.add_argument("-T", "--type_trans", action="store_true",
67                    help="Print type_transition rule differences")
68terule.add_argument("--type_change", action="store_true", help="Print type_change rule differences")
69terule.add_argument("--type_member", action="store_true",
70                    help="Print type_member rule differences")
71
72rbacrule = parser.add_argument_group("RBAC rule differences")
73rbacrule.add_argument("--role_allow", action="store_true", help="Print role allow rule differences")
74rbacrule.add_argument("--role_trans", action="store_true",
75                      help="Print role_transition rule differences")
76
77mlsrule = parser.add_argument_group("MLS rule differences")
78mlsrule.add_argument("--range_trans", action="store_true",
79                     help="Print range_transition rule differences")
80
81constrain = parser.add_argument_group("Constraint differences")
82constrain.add_argument("--constrain", action="store_true", help="Print constrain differences")
83constrain.add_argument("--mlsconstrain", action="store_true", help="Print mlsconstrain differences")
84constrain.add_argument("--validatetrans", action="store_true",
85                       help="Print validatetrans differences")
86constrain.add_argument("--mlsvalidatetrans", action="store_true",
87                       help="Print mlsvalidatetrans differences")
88
89labeling = parser.add_argument_group("labeling statement differences")
90labeling.add_argument("--initialsid", action="store_true", help="Print initial SID differences")
91labeling.add_argument("--fs_use", action="store_true", help="Print fs_use_* differences")
92labeling.add_argument("--genfscon", action="store_true", help="Print genfscon differences")
93labeling.add_argument("--netifcon", action="store_true", help="Print netifcon differences")
94labeling.add_argument("--nodecon", action="store_true", help="Print nodecon differences")
95labeling.add_argument("--portcon", action="store_true", help="Print portcon differences")
96
97other = parser.add_argument_group("other differences")
98other.add_argument("--default", action="store_true", help="Print default_* differences")
99other.add_argument("--property", action="store_true",
100                   help="Print policy property differences (handle_unknown, version, MLS)")
101other.add_argument("--polcap", action="store_true", help="Print policy capability differences")
102other.add_argument("--typebounds", action="store_true", help="Print typebounds differences")
103
104args = parser.parse_args()
105
106if args.A:
107    args.allow = True
108    args.allowxperm = True
109
110all_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
121if args.debug:
122    logging.basicConfig(level=logging.DEBUG,
123                        format='%(asctime)s|%(levelname)s|%(name)s|%(message)s')
124elif args.verbose:
125    logging.basicConfig(level=logging.INFO, format='%(message)s')
126else:
127    logging.basicConfig(level=logging.WARNING, format='%(message)s')
128
129try:
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
1360except Exception as err:
1361    if args.debug:
1362        logging.exception(str(err))
1363    else:
1364        print(err)
1365
1366    sys.exit(1)
1367