1#!/usr/bin/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", "--allow", action="store_true", help="Print allow rule differences") 55terule.add_argument("--neverallow", action="store_true", help="Print neverallow rule differences") 56terule.add_argument("--auditallow", action="store_true", help="Print auditallow rule differences") 57terule.add_argument("--dontaudit", action="store_true", help="Print dontaudit rule differences") 58terule.add_argument("-T", "--type_trans", action="store_true", 59 help="Print type_transition rule differences") 60terule.add_argument("--type_change", action="store_true", help="Print type_change rule differences") 61terule.add_argument("--type_member", action="store_true", 62 help="Print type_member rule differences") 63 64rbacrule = parser.add_argument_group("RBAC rule differences") 65rbacrule.add_argument("--role_allow", action="store_true", help="Print role allow rule differences") 66rbacrule.add_argument("--role_trans", action="store_true", 67 help="Print role_transition rule differences") 68 69mlsrule = parser.add_argument_group("MLS rule differences") 70mlsrule.add_argument("--range_trans", action="store_true", 71 help="Print range_transition rule differences") 72 73labeling = parser.add_argument_group("labeling statement differences") 74labeling.add_argument("--initialsid", action="store_true", help="Print initial SID differences") 75labeling.add_argument("--fs_use", action="store_true", help="Print fs_use_* differences") 76labeling.add_argument("--genfscon", action="store_true", help="Print genfscon differences") 77labeling.add_argument("--netifcon", action="store_true", help="Print netifcon differences") 78labeling.add_argument("--nodecon", action="store_true", help="Print nodecon differences") 79labeling.add_argument("--portcon", action="store_true", help="Print portcon differences") 80 81other = parser.add_argument_group("other differences") 82other.add_argument("--default", action="store_true", help="Print default_* differences") 83other.add_argument("--property", action="store_true", 84 help="Print policy property differences (handle_unknown, version, MLS)") 85other.add_argument("--polcap", action="store_true", help="Print policy capability differences") 86 87args = parser.parse_args() 88 89all_differences = not any((args.class_, args.common, args.type_, args.attribute, args.role, 90 args.user, args.bool_, args.sensitivity, args.category, args.level, 91 args.allow, args.neverallow, args.auditallow, args.dontaudit, 92 args.type_trans, args.type_change, args.type_member, args.role_allow, 93 args.role_trans, args.range_trans, args.initialsid, args.genfscon, 94 args.netifcon, args.nodecon, args.portcon, args.fs_use, args.polcap, 95 args.property, args.default)) 96 97if args.debug: 98 logging.basicConfig(level=logging.DEBUG, 99 format='%(asctime)s|%(levelname)s|%(name)s|%(message)s') 100elif args.verbose: 101 logging.basicConfig(level=logging.INFO, format='%(message)s') 102else: 103 logging.basicConfig(level=logging.WARNING, format='%(message)s') 104 105try: 106 p1 = setools.SELinuxPolicy(args.POLICY1[0]) 107 p2 = setools.SELinuxPolicy(args.POLICY2[0]) 108 diff = setools.PolicyDifference(p1, p2) 109 110 if all_differences or args.property: 111 print("Policy Properties ({0} Modified)".format(len(diff.modified_properties))) 112 113 if diff.modified_properties and not args.stats: 114 for name, added, removed in sorted(diff.modified_properties, key=lambda x: x.property): 115 print(" * {0} +{1} -{2}".format(name, added, removed)) 116 117 print() 118 119 if all_differences or args.common: 120 if diff.added_commons or diff.removed_commons or diff.modified_commons or args.common: 121 print("Commons ({0} Added, {1} Removed, {2} Modified)".format( 122 len(diff.added_commons), len(diff.removed_commons), len(diff.modified_commons))) 123 if diff.added_commons and not args.stats: 124 print(" Added Commons: {0}".format(len(diff.added_commons))) 125 for c in sorted(diff.added_commons): 126 print(" + {0}".format(c)) 127 if diff.removed_commons and not args.stats: 128 print(" Removed Commons: {0}".format(len(diff.removed_commons))) 129 for c in sorted(diff.removed_commons): 130 print(" - {0}".format(c)) 131 if diff.modified_commons and not args.stats: 132 print(" Modified Commons: {0}".format(len(diff.modified_commons))) 133 for name, mod in sorted(diff.modified_commons.items()): 134 change = [] 135 if mod.added_perms: 136 change.append("{0} Added permissions".format(len(mod.added_perms))) 137 if mod.removed_perms: 138 change.append("{0} Removed permissions".format(len(mod.removed_perms))) 139 140 print(" * {0} ({1})".format(name, ", ".join(change))) 141 for p in sorted(mod.added_perms): 142 print(" + {0}".format(p)) 143 for p in sorted(mod.removed_perms): 144 print(" - {0}".format(p)) 145 print() 146 147 if all_differences or args.class_: 148 if diff.added_classes or diff.removed_classes or diff.modified_classes or args.class_: 149 print("Classes ({0} Added, {1} Removed, {2} Modified)".format( 150 len(diff.added_classes), len(diff.removed_classes), len(diff.modified_classes))) 151 if diff.added_classes and not args.stats: 152 print(" Added Classes: {0}".format(len(diff.added_classes))) 153 for c in sorted(diff.added_classes): 154 print(" + {0}".format(c)) 155 if diff.removed_classes and not args.stats: 156 print(" Removed Classes: {0}".format(len(diff.removed_classes))) 157 for c in sorted(diff.removed_classes): 158 print(" - {0}".format(c)) 159 if diff.modified_classes and not args.stats: 160 print(" Modified Classes: {0}".format(len(diff.modified_classes))) 161 for name, mod in sorted(diff.modified_classes.items()): 162 change = [] 163 if mod.added_perms: 164 change.append("{0} Added permissions".format(len(mod.added_perms))) 165 if mod.removed_perms: 166 change.append("{0} Removed permissions".format(len(mod.removed_perms))) 167 168 print(" * {0} ({1})".format(name, ", ".join(change))) 169 for p in sorted(mod.added_perms): 170 print(" + {0}".format(p)) 171 for p in sorted(mod.removed_perms): 172 print(" - {0}".format(p)) 173 print() 174 175 if all_differences or args.bool_: 176 if diff.added_booleans or diff.removed_booleans or \ 177 diff.modified_booleans or args.bool_: 178 print("Booleans ({0} Added, {1} Removed, {2} Modified)".format( 179 len(diff.added_booleans), len(diff.removed_booleans), 180 len(diff.modified_booleans))) 181 if diff.added_booleans and not args.stats: 182 print(" Added Booleans: {0}".format(len(diff.added_booleans))) 183 for a in sorted(diff.added_booleans): 184 print(" + {0}".format(a)) 185 if diff.removed_booleans and not args.stats: 186 print(" Removed Booleans: {0}".format(len(diff.removed_booleans))) 187 for a in sorted(diff.removed_booleans): 188 print(" - {0}".format(a)) 189 if diff.modified_booleans and not args.stats: 190 print(" Modified Booleans: {0}".format(len(diff.modified_booleans))) 191 for name, mod in sorted(diff.modified_booleans.items()): 192 print(" * {0} (Modified default state)".format(name)) 193 print(" + {0}".format(mod.added_state)) 194 print(" - {0}".format(mod.removed_state)) 195 196 print() 197 198 if all_differences or args.role: 199 if diff.added_roles or diff.removed_roles or diff.modified_roles or args.role: 200 print("Roles ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_roles), 201 len(diff.removed_roles), 202 len(diff.modified_roles))) 203 if diff.added_roles and not args.stats: 204 print(" Added Roles: {0}".format(len(diff.added_roles))) 205 for r in sorted(diff.added_roles): 206 print(" + {0}".format(r)) 207 if diff.removed_roles and not args.stats: 208 print(" Removed Roles: {0}".format(len(diff.removed_roles))) 209 for r in sorted(diff.removed_roles): 210 print(" - {0}".format(r)) 211 if diff.modified_roles and not args.stats: 212 print(" Modified Roles: {0}".format(len(diff.modified_roles))) 213 for name, mod in sorted(diff.modified_roles.items()): 214 change = [] 215 if mod.added_types: 216 change.append("{0} Added types".format(len(mod.added_types))) 217 if mod.removed_types: 218 change.append("{0} Removed types".format(len(mod.removed_types))) 219 220 print(" * {0} ({1})".format(name, ", ".join(change))) 221 for t in sorted(mod.added_types): 222 print(" + {0}".format(t)) 223 for t in sorted(mod.removed_types): 224 print(" - {0}".format(t)) 225 print() 226 227 if all_differences or args.type_: 228 if diff.added_types or diff.removed_types or diff.modified_types or args.type_: 229 print("Types ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_types), 230 len(diff.removed_types), 231 len(diff.modified_types))) 232 if diff.added_types and not args.stats: 233 print(" Added Types: {0}".format(len(diff.added_types))) 234 for r in sorted(diff.added_types): 235 print(" + {0}".format(r)) 236 if diff.removed_types and not args.stats: 237 print(" Removed Types: {0}".format(len(diff.removed_types))) 238 for r in sorted(diff.removed_types): 239 print(" - {0}".format(r)) 240 if diff.modified_types and not args.stats: 241 print(" Modified Types: {0}".format(len(diff.modified_types))) 242 for name, mod in sorted(diff.modified_types.items()): 243 change = [] 244 if mod.added_attributes: 245 change.append("{0} Added attributes".format(len(mod.added_attributes))) 246 if mod.removed_attributes: 247 change.append("{0} Removed attributes".format(len(mod.removed_attributes))) 248 if mod.added_aliases: 249 change.append("{0} Added aliases".format(len(mod.added_aliases))) 250 if mod.removed_aliases: 251 change.append("{0} Removed aliases".format(len(mod.removed_aliases))) 252 if mod.modified_permissive: 253 if mod.permissive: 254 change.append("Removed permissive") 255 else: 256 change.append("Added permissive") 257 258 print(" * {0} ({1})".format(name, ", ".join(change))) 259 if mod.added_attributes or mod.removed_attributes: 260 print(" Attributes:") 261 for t in sorted(mod.added_attributes): 262 print(" + {0}".format(t)) 263 for t in sorted(mod.removed_attributes): 264 print(" - {0}".format(t)) 265 266 if mod.added_aliases or mod.removed_aliases: 267 print(" Aliases:") 268 for t in sorted(mod.added_aliases): 269 print(" + {0}".format(t)) 270 for t in sorted(mod.removed_aliases): 271 print(" - {0}".format(t)) 272 273 print() 274 275 if all_differences or args.attribute: 276 if diff.added_type_attributes or diff.removed_type_attributes or \ 277 diff.modified_type_attributes or args.attribute: 278 print("Type Attributes ({0} Added, {1} Removed, {2} Modified)".format( 279 len(diff.added_type_attributes), len(diff.removed_type_attributes), 280 len(diff.modified_type_attributes))) 281 if diff.added_type_attributes and not args.stats: 282 print(" Added Type Attributes: {0}".format(len(diff.added_type_attributes))) 283 for a in sorted(diff.added_type_attributes): 284 print(" + {0}".format(a)) 285 if diff.removed_type_attributes and not args.stats: 286 print(" Removed Type Attributes: {0}".format(len(diff.removed_type_attributes))) 287 for a in sorted(diff.removed_type_attributes): 288 print(" - {0}".format(a)) 289 if diff.modified_type_attributes and not args.stats: 290 print(" Modified Type Attributes: {0}".format(len(diff.modified_type_attributes))) 291 for name, mod in sorted(diff.modified_type_attributes.items()): 292 change = [] 293 if mod.added_types: 294 change.append("{0} Added types".format(len(mod.added_types))) 295 if mod.removed_types: 296 change.append("{0} Removed types".format(len(mod.removed_types))) 297 298 print(" * {0} ({1})".format(name, ", ".join(change))) 299 for t in sorted(mod.added_types): 300 print(" + {0}".format(t)) 301 for t in sorted(mod.removed_types): 302 print(" - {0}".format(t)) 303 print() 304 305 if all_differences or args.user: 306 if diff.added_users or diff.removed_users or diff.modified_users or args.user: 307 print("Users ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_users), 308 len(diff.removed_users), 309 len(diff.modified_users))) 310 if diff.added_users and not args.stats: 311 print(" Added Users: {0}".format(len(diff.added_users))) 312 for u in sorted(diff.added_users): 313 print(" + {0}".format(u)) 314 if diff.removed_users and not args.stats: 315 print(" Removed Users: {0}".format(len(diff.removed_users))) 316 for u in sorted(diff.removed_users): 317 print(" - {0}".format(u)) 318 if diff.modified_users and not args.stats: 319 print(" Modified Users: {0}".format(len(diff.modified_users))) 320 for name, mod in sorted(diff.modified_users.items()): 321 change = [] 322 if mod.added_roles: 323 change.append("{0} Added roles".format(len(mod.added_roles))) 324 if mod.removed_roles: 325 change.append("{0} Removed roles".format(len(mod.removed_roles))) 326 if mod.removed_level: 327 change.append("Modified default level") 328 if mod.removed_range: 329 change.append("Modified range") 330 331 print(" * {0} ({1})".format(name, ", ".join(change))) 332 if mod.added_roles or mod.removed_roles: 333 print(" Roles:") 334 for t in sorted(mod.added_roles): 335 print(" + {0}".format(t)) 336 for t in sorted(mod.removed_roles): 337 print(" - {0}".format(t)) 338 339 if mod.removed_level: 340 print(" Default level:") 341 print(" + {0}".format(mod.added_level)) 342 print(" - {0}".format(mod.removed_level)) 343 344 if mod.removed_range: 345 print(" Range:") 346 print(" + {0}".format(mod.added_range)) 347 print(" - {0}".format(mod.removed_range)) 348 print() 349 350 if all_differences or args.category: 351 if diff.added_categories or diff.removed_categories or diff.modified_categories \ 352 or args.category: 353 print("Categories ({0} Added, {1} Removed, {2} Modified)".format( 354 len(diff.added_categories), len(diff.removed_categories), 355 len(diff.modified_categories))) 356 if diff.added_categories and not args.stats: 357 print(" Added Categories: {0}".format(len(diff.added_categories))) 358 for c in sorted(diff.added_categories): 359 print(" + {0}".format(c)) 360 if diff.removed_categories and not args.stats: 361 print(" Removed Categories: {0}".format(len(diff.removed_categories))) 362 for c in sorted(diff.removed_categories): 363 print(" - {0}".format(c)) 364 if diff.modified_categories and not args.stats: 365 print(" Modified Categories: {0}".format(len(diff.modified_categories))) 366 for name, mod in sorted(diff.modified_categories.items()): 367 change = [] 368 if mod.added_aliases: 369 change.append("{0} Added Aliases".format(len(mod.added_aliases))) 370 if mod.removed_aliases: 371 change.append("{0} Removed Aliases".format(len(mod.removed_aliases))) 372 373 print(" * {0} ({1})".format(name, ", ".join(change))) 374 print(" Aliases:") 375 for a in sorted(mod.added_aliases): 376 print(" + {0}".format(a)) 377 for a in sorted(mod.removed_aliases): 378 print(" - {0}".format(a)) 379 380 print() 381 382 if all_differences or args.sensitivity: 383 if diff.added_sensitivities or diff.removed_sensitivities or diff.modified_sensitivities \ 384 or args.sensitivity: 385 print("Sensitivities ({0} Added, {1} Removed, {2} Modified)".format( 386 len(diff.added_sensitivities), len(diff.removed_sensitivities), 387 len(diff.modified_sensitivities))) 388 if diff.added_sensitivities and not args.stats: 389 print(" Added Sensitivites: {0}".format(len(diff.added_sensitivities))) 390 for s in sorted(diff.added_sensitivities): 391 print(" + {0}".format(s)) 392 if diff.removed_sensitivities and not args.stats: 393 print(" Removed Sensitivities: {0}".format(len(diff.removed_sensitivities))) 394 for s in sorted(diff.removed_sensitivities): 395 print(" - {0}".format(s)) 396 if diff.modified_sensitivities and not args.stats: 397 print(" Modified Sensitivities: {0}".format(len(diff.modified_sensitivities))) 398 for name, mod in sorted(diff.modified_sensitivities.items()): 399 change = [] 400 if mod.added_aliases: 401 change.append("{0} Added Aliases".format(len(mod.added_aliases))) 402 if mod.removed_aliases: 403 change.append("{0} Removed Aliases".format(len(mod.removed_aliases))) 404 405 print(" * {0} ({1})".format(name, ", ".join(change))) 406 print(" Aliases:") 407 for a in sorted(mod.added_aliases): 408 print(" + {0}".format(a)) 409 for a in sorted(mod.removed_aliases): 410 print(" - {0}".format(a)) 411 412 print() 413 414 if all_differences or args.level: 415 if diff.added_levels or diff.removed_levels or \ 416 diff.modified_levels or args.level: 417 print("Levels ({0} Added, {1} Removed, {2} Modified)".format( 418 len(diff.added_levels), len(diff.removed_levels), 419 len(diff.modified_levels))) 420 if diff.added_levels and not args.stats: 421 print(" Added Levels: {0}".format(len(diff.added_levels))) 422 for l in sorted(diff.added_levels): 423 print(" + {0}".format(l)) 424 if diff.removed_levels and not args.stats: 425 print(" Removed Levels: {0}".format(len(diff.removed_levels))) 426 for l in sorted(diff.removed_levels): 427 print(" - {0}".format(l)) 428 if diff.modified_levels and not args.stats: 429 print(" Modified Levels: {0}".format(len(diff.modified_levels))) 430 for level, added_categories, removed_categories, _ in sorted(diff.modified_levels, 431 key=lambda x: x.level): 432 change = [] 433 if added_categories: 434 change.append("{0} Added Categories".format(len(added_categories))) 435 if removed_categories: 436 change.append("{0} Removed Categories".format(len(removed_categories))) 437 438 print(" * {0} ({1})".format(level.sensitivity, ", ".join(change))) 439 for c in sorted(added_categories): 440 print(" + {0}".format(c)) 441 for c in sorted(removed_categories): 442 print(" - {0}".format(c)) 443 print() 444 445 if all_differences or args.allow: 446 if diff.added_allows or diff.removed_allows or diff.modified_allows or args.allow: 447 print("Allow Rules ({0} Added, {1} Removed, {2} Modified)".format( 448 len(diff.added_allows), len(diff.removed_allows), len(diff.modified_allows))) 449 450 if diff.added_allows and not args.stats: 451 print(" Added Allow Rules: {0}".format(len(diff.added_allows))) 452 for r in sorted(diff.added_allows): 453 print(" + {0}".format(r)) 454 455 if diff.removed_allows and not args.stats: 456 print(" Removed Allow Rules: {0}".format(len(diff.removed_allows))) 457 for r in sorted(diff.removed_allows): 458 print(" - {0}".format(r)) 459 460 if diff.modified_allows and not args.stats: 461 print(" Modified Allow Rules: {0}".format(len(diff.modified_allows))) 462 463 for rule, added_perms, removed_perms, matched_perms in sorted(diff.modified_allows, 464 key=lambda x: x.rule): 465 perms = " ".join(chain((p for p in matched_perms), 466 ("+" + p for p in added_perms), 467 ("-" + p for p in removed_perms))) 468 rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format( 469 rule, perms) 470 471 try: 472 rule_string += " [ {0} ]".format(rule.conditional) 473 except AttributeError: 474 pass 475 print(" * {0}".format(rule_string)) 476 477 print() 478 479 if all_differences or args.neverallow: 480 if diff.added_neverallows or diff.removed_neverallows or diff.modified_neverallows or \ 481 args.neverallow: 482 print("Neverallow Rules ({0} Added, {1} Removed, {2} Modified)".format( 483 len(diff.added_neverallows), len(diff.removed_neverallows), 484 len(diff.modified_neverallows))) 485 486 if diff.added_neverallows and not args.stats: 487 print(" Added Neverallow Rules: {0}".format(len(diff.added_neverallows))) 488 for r in sorted(diff.added_neverallows): 489 print(" + {0}".format(r)) 490 491 if diff.removed_neverallows and not args.stats: 492 print(" Removed Neverallow Rules: {0}".format(len(diff.removed_neverallows))) 493 for r in sorted(diff.removed_neverallows): 494 print(" - {0}".format(r)) 495 496 if diff.modified_neverallows and not args.stats: 497 print(" Modified Neverallow Rules: {0}".format(len(diff.modified_neverallows))) 498 499 for rule, added_perms, removed_perms, matched_perms in sorted( 500 diff.modified_neverallows, key=lambda x: x.rule): 501 perms = " ".join(chain((p for p in matched_perms), 502 ("+" + p for p in added_perms), 503 ("-" + p for p in removed_perms))) 504 rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format( 505 rule, perms) 506 507 try: 508 rule_string += " [ {0} ]".format(rule.conditional) 509 except AttributeError: 510 pass 511 print(" * {0}".format(rule_string)) 512 513 print() 514 515 if all_differences or args.auditallow: 516 if diff.added_auditallows or diff.removed_auditallows or diff.modified_auditallows or \ 517 args.auditallow: 518 print("Auditallow Rules ({0} Added, {1} Removed, {2} Modified)".format( 519 len(diff.added_auditallows), len(diff.removed_auditallows), 520 len(diff.modified_auditallows))) 521 522 if diff.added_auditallows and not args.stats: 523 print(" Added Auditallow Rules: {0}".format(len(diff.added_auditallows))) 524 for r in sorted(diff.added_auditallows): 525 print(" + {0}".format(r)) 526 527 if diff.removed_auditallows and not args.stats: 528 print(" Removed Auditallow Rules: {0}".format(len(diff.removed_auditallows))) 529 for r in sorted(diff.removed_auditallows): 530 print(" - {0}".format(r)) 531 532 if diff.modified_auditallows and not args.stats: 533 print(" Modified Auditallow Rules: {0}".format(len(diff.modified_auditallows))) 534 535 for rule, added_perms, removed_perms, matched_perms in sorted( 536 diff.modified_auditallows, key=lambda x: x.rule): 537 perms = " ".join(chain((p for p in matched_perms), 538 ("+" + p for p in added_perms), 539 ("-" + p for p in removed_perms))) 540 rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format( 541 rule, perms) 542 543 try: 544 rule_string += " [ {0} ]".format(rule.conditional) 545 except AttributeError: 546 pass 547 print(" * {0}".format(rule_string)) 548 549 print() 550 551 if all_differences or args.dontaudit: 552 if diff.added_dontaudits or diff.removed_dontaudits or diff.modified_dontaudits or \ 553 args.dontaudit: 554 print("Dontaudit Rules ({0} Added, {1} Removed, {2} Modified)".format( 555 len(diff.added_dontaudits), len(diff.removed_dontaudits), 556 len(diff.modified_dontaudits))) 557 558 if diff.added_dontaudits and not args.stats: 559 print(" Added Dontaudit Rules: {0}".format(len(diff.added_dontaudits))) 560 for r in sorted(diff.added_dontaudits): 561 print(" + {0}".format(r)) 562 563 if diff.removed_dontaudits and not args.stats: 564 print(" Removed Dontaudit Rules: {0}".format(len(diff.removed_dontaudits))) 565 for r in sorted(diff.removed_dontaudits): 566 print(" - {0}".format(r)) 567 568 if diff.modified_dontaudits and not args.stats: 569 print(" Modified Dontaudit Rules: {0}".format(len(diff.modified_dontaudits))) 570 571 for rule, added_perms, removed_perms, matched_perms in sorted( 572 diff.modified_dontaudits, key=lambda x: x.rule): 573 perms = " ".join(chain((p for p in matched_perms), 574 ("+" + p for p in added_perms), 575 ("-" + p for p in removed_perms))) 576 rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format( 577 rule, perms) 578 579 try: 580 rule_string += " [ {0} ]".format(rule.conditional) 581 except AttributeError: 582 pass 583 print(" * {0}".format(rule_string)) 584 585 print() 586 587 if all_differences or args.type_trans: 588 if diff.added_type_transitions or diff.removed_type_transitions or \ 589 diff.modified_type_transitions or args.type_trans: 590 print("Type_transition Rules ({0} Added, {1} Removed, {2} Modified)".format( 591 len(diff.added_type_transitions), len(diff.removed_type_transitions), 592 len(diff.modified_type_transitions))) 593 594 if diff.added_type_transitions and not args.stats: 595 print(" Added Type_transition Rules: {0}".format( 596 len(diff.added_type_transitions))) 597 for r in sorted(diff.added_type_transitions): 598 print(" + {0}".format(r)) 599 600 if diff.removed_type_transitions and not args.stats: 601 print(" Removed Type_transition Rules: {0}".format( 602 len(diff.removed_type_transitions))) 603 for r in sorted(diff.removed_type_transitions): 604 print(" - {0}".format(r)) 605 606 if diff.modified_type_transitions and not args.stats: 607 print(" Modified Type_transition Rules: {0}".format( 608 len(diff.modified_type_transitions))) 609 610 for rule, added_default, removed_default in sorted(diff.modified_type_transitions, 611 key=lambda x: x.rule): 612 rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format( 613 rule, added_default, removed_default) 614 615 try: 616 rule_string += " {0}".format(rule.filename) 617 except AttributeError: 618 pass 619 620 rule_string += ";" 621 622 try: 623 rule_string += " [ {0} ]".format(rule.conditional) 624 except AttributeError: 625 pass 626 627 print(" * {0}".format(rule_string)) 628 629 print() 630 631 if all_differences or args.type_change: 632 if diff.added_type_changes or diff.removed_type_changes or \ 633 diff.modified_type_changes or args.type_change: 634 print("Type_change Rules ({0} Added, {1} Removed, {2} Modified)".format( 635 len(diff.added_type_changes), len(diff.removed_type_changes), 636 len(diff.modified_type_changes))) 637 638 if diff.added_type_changes and not args.stats: 639 print(" Added Type_change Rules: {0}".format(len(diff.added_type_changes))) 640 for r in sorted(diff.added_type_changes): 641 print(" + {0}".format(r)) 642 643 if diff.removed_type_changes and not args.stats: 644 print(" Removed Type_change Rules: {0}".format(len(diff.removed_type_changes))) 645 for r in sorted(diff.removed_type_changes): 646 print(" - {0}".format(r)) 647 648 if diff.modified_type_changes and not args.stats: 649 print(" Modified Type_change Rules: {0}".format(len(diff.modified_type_changes))) 650 651 for rule, added_default, removed_default in sorted(diff.modified_type_changes, 652 key=lambda x: x.rule): 653 rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format( 654 rule, added_default, removed_default) 655 656 try: 657 rule_string += " {0}".format(rule.filename) 658 except AttributeError: 659 pass 660 661 rule_string += ";" 662 663 try: 664 rule_string += " [ {0} ]".format(rule.conditional) 665 except AttributeError: 666 pass 667 668 print(" * {0}".format(rule_string)) 669 670 print() 671 672 if all_differences or args.type_member: 673 if diff.added_type_members or diff.removed_type_members or \ 674 diff.modified_type_members or args.type_member: 675 print("Type_member Rules ({0} Added, {1} Removed, {2} Modified)".format( 676 len(diff.added_type_members), len(diff.removed_type_members), 677 len(diff.modified_type_members))) 678 679 if diff.added_type_members and not args.stats: 680 print(" Added Type_member Rules: {0}".format(len(diff.added_type_members))) 681 for r in sorted(diff.added_type_members): 682 print(" + {0}".format(r)) 683 684 if diff.removed_type_members and not args.stats: 685 print(" Removed Type_member Rules: {0}".format(len(diff.removed_type_members))) 686 for r in sorted(diff.removed_type_members): 687 print(" - {0}".format(r)) 688 689 if diff.modified_type_members and not args.stats: 690 print(" Modified Type_member Rules: {0}".format(len(diff.modified_type_members))) 691 692 for rule, added_default, removed_default in sorted(diff.modified_type_members, 693 key=lambda x: x.rule): 694 rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format( 695 rule, added_default, removed_default) 696 697 try: 698 rule_string += " {0}".format(rule.filename) 699 except AttributeError: 700 pass 701 702 rule_string += ";" 703 704 try: 705 rule_string += " [ {0} ]".format(rule.conditional) 706 except AttributeError: 707 pass 708 709 print(" * {0}".format(rule_string)) 710 711 print() 712 713 if all_differences or args.role_allow: 714 if diff.added_role_allows or diff.removed_role_allows or args.role_allow: 715 print("Role allow Rules ({0} Added, {1} Removed)".format( 716 len(diff.added_role_allows), len(diff.removed_role_allows))) 717 718 if diff.added_role_allows and not args.stats: 719 print(" Added Role allow Rules: {0}".format( 720 len(diff.added_role_allows))) 721 for r in sorted(diff.added_role_allows): 722 print(" + {0}".format(r)) 723 724 if diff.removed_role_allows and not args.stats: 725 print(" Removed Role allow Rules: {0}".format( 726 len(diff.removed_role_allows))) 727 for r in sorted(diff.removed_role_allows): 728 print(" - {0}".format(r)) 729 730 print() 731 732 if all_differences or args.role_trans: 733 if diff.added_role_transitions or diff.removed_role_transitions or \ 734 diff.modified_role_transitions or args.role_trans: 735 print("Role_transition Rules ({0} Added, {1} Removed, {2} Modified)".format( 736 len(diff.added_role_transitions), len(diff.removed_role_transitions), 737 len(diff.modified_role_transitions))) 738 739 if diff.added_role_transitions and not args.stats: 740 print(" Added Role_transition Rules: {0}".format( 741 len(diff.added_role_transitions))) 742 for r in sorted(diff.added_role_transitions): 743 print(" + {0}".format(r)) 744 745 if diff.removed_role_transitions and not args.stats: 746 print(" Removed Role_transition Rules: {0}".format( 747 len(diff.removed_role_transitions))) 748 for r in sorted(diff.removed_role_transitions): 749 print(" - {0}".format(r)) 750 751 if diff.modified_role_transitions and not args.stats: 752 print(" Modified Role_transition Rules: {0}".format( 753 len(diff.modified_role_transitions))) 754 755 for rule, added_default, removed_default in sorted(diff.modified_role_transitions, 756 key=lambda x: x.rule): 757 rule_string = \ 758 "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format( 759 rule, added_default, removed_default) 760 761 print(" * {0}".format(rule_string)) 762 763 print() 764 765 if all_differences or args.range_trans: 766 if diff.added_range_transitions or diff.removed_range_transitions or \ 767 diff.modified_range_transitions or args.range_trans: 768 print("Range_transition Rules ({0} Added, {1} Removed, {2} Modified)".format( 769 len(diff.added_range_transitions), len(diff.removed_range_transitions), 770 len(diff.modified_range_transitions))) 771 772 if diff.added_range_transitions and not args.stats: 773 print(" Added Range_transition Rules: {0}".format( 774 len(diff.added_range_transitions))) 775 for r in sorted(diff.added_range_transitions): 776 print(" + {0}".format(r)) 777 778 if diff.removed_range_transitions and not args.stats: 779 print(" Removed Range_transition Rules: {0}".format( 780 len(diff.removed_range_transitions))) 781 for r in sorted(diff.removed_range_transitions): 782 print(" - {0}".format(r)) 783 784 if diff.modified_range_transitions and not args.stats: 785 print(" Modified Range_transition Rules: {0}".format( 786 len(diff.modified_range_transitions))) 787 788 for rule, added_default, removed_default in sorted(diff.modified_range_transitions, 789 key=lambda x: x.rule): 790 # added brackets around range change for clarity since ranges 791 # can have '-' and spaces. 792 rule_string = \ 793 "{0.ruletype} {0.source} {0.target}:{0.tclass} +[{1}] -[{2}]".format( 794 rule, added_default, removed_default) 795 796 print(" * {0}".format(rule_string)) 797 798 print() 799 800 if all_differences or args.initialsid: 801 if diff.added_initialsids or diff.removed_initialsids or diff.modified_initialsids \ 802 or args.initialsid: 803 print("Initial SIDs ({0} Added, {1} Removed, {2} Modified)".format( 804 len(diff.added_initialsids), len(diff.removed_initialsids), 805 len(diff.modified_initialsids))) 806 if diff.added_initialsids and not args.stats: 807 print(" Added Initial SIDs: {0}".format(len(diff.added_initialsids))) 808 for s in sorted(diff.added_initialsids): 809 print(" + {0}".format(s.statement())) 810 if diff.removed_initialsids and not args.stats: 811 print(" Removed Initial SIDs: {0}".format(len(diff.removed_initialsids))) 812 for s in sorted(diff.removed_initialsids): 813 print(" - {0}".format(s.statement())) 814 if diff.modified_initialsids and not args.stats: 815 print(" Modified Initial SIDs: {0}".format(len(diff.modified_initialsids))) 816 for name, mod in sorted(diff.modified_initialsids.items()): 817 print(" * {0} +[{1.added_context}] -[{1.removed_context}];".format( 818 name, mod)) 819 820 print() 821 822 if all_differences or args.fs_use: 823 if diff.added_fs_uses or diff.removed_fs_uses or diff.modified_fs_uses \ 824 or args.fs_use: 825 print("Fs_use ({0} Added, {1} Removed, {2} Modified)".format( 826 len(diff.added_fs_uses), len(diff.removed_fs_uses), 827 len(diff.modified_fs_uses))) 828 if diff.added_fs_uses and not args.stats: 829 print(" Added Fs_use: {0}".format(len(diff.added_fs_uses))) 830 for s in sorted(diff.added_fs_uses): 831 print(" + {0}".format(s)) 832 if diff.removed_fs_uses and not args.stats: 833 print(" Removed Fs_use: {0}".format(len(diff.removed_fs_uses))) 834 for s in sorted(diff.removed_fs_uses): 835 print(" - {0}".format(s)) 836 if diff.modified_fs_uses and not args.stats: 837 print(" Modified Fs_use: {0}".format(len(diff.modified_fs_uses))) 838 for entry in sorted(diff.modified_fs_uses, key=lambda x: x.rule): 839 print(" * {0.ruletype} {0.fs} +[{1}] -[{2}];".format( 840 entry.rule, entry.added_context, entry.removed_context)) 841 842 print() 843 844 if all_differences or args.genfscon: 845 if diff.added_genfscons or diff.removed_genfscons or diff.modified_genfscons \ 846 or args.genfscon: 847 print("Genfscons ({0} Added, {1} Removed, {2} Modified)".format( 848 len(diff.added_genfscons), len(diff.removed_genfscons), 849 len(diff.modified_genfscons))) 850 if diff.added_genfscons and not args.stats: 851 print(" Added Genfscons: {0}".format(len(diff.added_genfscons))) 852 for s in sorted(diff.added_genfscons): 853 print(" + {0}".format(s)) 854 if diff.removed_genfscons and not args.stats: 855 print(" Removed Genfscons: {0}".format(len(diff.removed_genfscons))) 856 for s in sorted(diff.removed_genfscons): 857 print(" - {0}".format(s)) 858 if diff.modified_genfscons and not args.stats: 859 print(" Modified Genfscons: {0}".format(len(diff.modified_genfscons))) 860 for entry in sorted(diff.modified_genfscons, key=lambda x: x.rule): 861 print(" * genfscon {0.fs} {0.path} {0.filetype} +[{1}] -[{2}];".format( 862 entry.rule, entry.added_context, entry.removed_context)) 863 864 print() 865 866 if all_differences or args.netifcon: 867 if diff.added_netifcons or diff.removed_netifcons or \ 868 diff.modified_netifcons or args.netifcon: 869 print("Netifcons ({0} Added, {1} Removed, {2} Modified)".format( 870 len(diff.added_netifcons), len(diff.removed_netifcons), 871 len(diff.modified_netifcons))) 872 if diff.added_netifcons and not args.stats: 873 print(" Added Netifcons: {0}".format(len(diff.added_netifcons))) 874 for n in sorted(diff.added_netifcons): 875 print(" + {0}".format(n)) 876 if diff.removed_netifcons and not args.stats: 877 print(" Removed Netifcons: {0}".format(len(diff.removed_netifcons))) 878 for n in sorted(diff.removed_netifcons): 879 print(" - {0}".format(n)) 880 if diff.modified_netifcons and not args.stats: 881 print(" Modified Netifcons: {0}".format(len(diff.modified_netifcons))) 882 for entry in sorted(diff.modified_netifcons, key=lambda x: x.rule): 883 # This output is different than other statements because 884 # it becomes difficult to read if this was condensed 885 # into a single line, especially if both contexts 886 # are modified. 887 change = [] 888 if entry.removed_context: 889 change.append("Modified Context") 890 if entry.removed_packet: 891 change.append("Modified Packet Context") 892 893 print(" * {0.netif} ({1})".format(entry.rule, ", ".join(change))) 894 895 if entry.removed_context: 896 print(" Context:") 897 print(" + {0}".format(entry.added_context)) 898 print(" - {0}".format(entry.removed_context)) 899 if entry.removed_packet: 900 print(" Packet Context:") 901 print(" + {0}".format(entry.added_packet)) 902 print(" - {0}".format(entry.removed_packet)) 903 904 print() 905 906 if all_differences or args.nodecon: 907 if diff.added_nodecons or diff.removed_nodecons or diff.modified_nodecons \ 908 or args.nodecon: 909 print("Nodecons ({0} Added, {1} Removed, {2} Modified)".format( 910 len(diff.added_nodecons), len(diff.removed_nodecons), 911 len(diff.modified_nodecons))) 912 if diff.added_nodecons and not args.stats: 913 print(" Added Nodecons: {0}".format(len(diff.added_nodecons))) 914 for n in sorted(diff.added_nodecons): 915 print(" + {0}".format(n)) 916 if diff.removed_nodecons and not args.stats: 917 print(" Removed Nodecons: {0}".format(len(diff.removed_nodecons))) 918 for n in sorted(diff.removed_nodecons): 919 print(" - {0}".format(n)) 920 if diff.modified_nodecons and not args.stats: 921 print(" Modified Nodecons: {0}".format(len(diff.modified_nodecons))) 922 for con, added_context, removed_context in sorted(diff.modified_nodecons, 923 key=lambda x: x.rule): 924 print(" * nodecon {0.address} {0.netmask} +[{1}] -[{2}];".format( 925 con, added_context, removed_context)) 926 927 print() 928 929 if all_differences or args.portcon: 930 if diff.added_portcons or diff.removed_portcons or diff.modified_portcons \ 931 or args.portcon: 932 print("Portcons ({0} Added, {1} Removed, {2} Modified)".format( 933 len(diff.added_portcons), len(diff.removed_portcons), 934 len(diff.modified_portcons))) 935 if diff.added_portcons and not args.stats: 936 print(" Added Portcons: {0}".format(len(diff.added_portcons))) 937 for n in sorted(diff.added_portcons): 938 print(" + {0}".format(n)) 939 if diff.removed_portcons and not args.stats: 940 print(" Removed Portcons: {0}".format(len(diff.removed_portcons))) 941 for n in sorted(diff.removed_portcons): 942 print(" - {0}".format(n)) 943 if diff.modified_portcons and not args.stats: 944 print(" Modified Portcons: {0}".format(len(diff.modified_portcons))) 945 for con, added_context, removed_context in sorted(diff.modified_portcons, 946 key=lambda x: x.rule): 947 low, high = con.ports 948 if low == high: 949 print(" * portcon {0.protocol} {1} +[{2}] -[{3}];".format( 950 con, low, added_context, removed_context)) 951 else: 952 print(" * portcon {0.protocol} {1}-{2} +[{3}] -[{4}];".format( 953 con, low, high, added_context, removed_context)) 954 955 print() 956 957 if all_differences or args.polcap: 958 if diff.added_polcaps or diff.removed_polcaps or args.polcap: 959 print("Policy Capabilities ({0} Added, {1} Removed)".format( 960 len(diff.added_polcaps), len(diff.removed_polcaps))) 961 if diff.added_polcaps and not args.stats: 962 print(" Added Policy Capabilities: {0}".format(len(diff.added_polcaps))) 963 for n in sorted(diff.added_polcaps): 964 print(" + {0}".format(n)) 965 if diff.removed_polcaps and not args.stats: 966 print(" Removed Policy Capabilities: {0}".format(len(diff.removed_polcaps))) 967 for n in sorted(diff.removed_polcaps): 968 print(" - {0}".format(n)) 969 970 print() 971 972 if all_differences or args.default: 973 if diff.added_defaults or diff.removed_defaults or args.default: 974 print("Defaults ({0} Added, {1} Removed, {2} Modified)".format( 975 len(diff.added_defaults), len(diff.removed_defaults), len(diff.modified_defaults))) 976 if diff.added_defaults and not args.stats: 977 print(" Added Defaults: {0}".format(len(diff.added_defaults))) 978 for d in sorted(diff.added_defaults): 979 print(" + {0}".format(d)) 980 if diff.removed_defaults and not args.stats: 981 print(" Removed Defaults: {0}".format(len(diff.removed_defaults))) 982 for d in sorted(diff.removed_defaults): 983 print(" - {0}".format(d)) 984 if diff.modified_defaults and not args.stats: 985 print(" Modified Defaults: {0}".format(len(diff.modified_defaults))) 986 for default, added_default, removed_default, added_range, removed_range in sorted( 987 diff.modified_defaults, key=lambda x: x.rule): 988 line = " * {0.ruletype} {0.tclass} ".format(default) 989 if removed_default: 990 line += "+{0} -{1}".format(added_default, removed_default) 991 else: 992 line += default.default 993 994 if removed_range: 995 line += " +{0} -{1};".format(added_range, removed_range) 996 else: 997 try: 998 line += " {0};".format(default.default_range) 999 except AttributeError: 1000 line += ";" 1001 print(line) 1002 1003 print() 1004 1005except Exception as err: 1006 if args.debug: 1007 import traceback 1008 traceback.print_exc() 1009 else: 1010 print(err) 1011 1012 sys.exit(1) 1013