1#!/usr/bin/python 2 3# Author: Dan Walsh <dwalsh@redhat.com> 4# Author: Ryan Hallisey <rhallise@redhat.com> 5# Author: Jason Zaman <perfinion@gentoo.org> 6 7import errno 8import selinux 9import setools 10import glob 11import sepolgen.defaults as defaults 12import sepolgen.interfaces as interfaces 13import sys 14import os 15import re 16import gzip 17 18PROGNAME = "policycoreutils" 19try: 20 import gettext 21 kwargs = {} 22 if sys.version_info < (3,): 23 kwargs['unicode'] = True 24 gettext.install(PROGNAME, 25 localedir="/usr/share/locale", 26 codeset='utf-8', 27 **kwargs) 28except: 29 try: 30 import builtins 31 builtins.__dict__['_'] = str 32 except ImportError: 33 import __builtin__ 34 __builtin__.__dict__['_'] = unicode 35 36TYPE = 1 37ROLE = 2 38ATTRIBUTE = 3 39PORT = 4 40USER = 5 41BOOLEAN = 6 42TCLASS = 7 43 44ALLOW = 'allow' 45AUDITALLOW = 'auditallow' 46NEVERALLOW = 'neverallow' 47DONTAUDIT = 'dontaudit' 48SOURCE = 'source' 49TARGET = 'target' 50PERMS = 'permlist' 51CLASS = 'class' 52TRANSITION = 'transition' 53ROLE_ALLOW = 'role_allow' 54 55 56# Autofill for adding files ************************* 57DEFAULT_DIRS = {} 58DEFAULT_DIRS["/etc"] = "etc_t" 59DEFAULT_DIRS["/tmp"] = "tmp_t" 60DEFAULT_DIRS["/usr/lib/systemd/system"] = "unit_file_t" 61DEFAULT_DIRS["/lib/systemd/system"] = "unit_file_t" 62DEFAULT_DIRS["/etc/systemd/system"] = "unit_file_t" 63DEFAULT_DIRS["/var/cache"] = "var_cache_t" 64DEFAULT_DIRS["/var/lib"] = "var_lib_t" 65DEFAULT_DIRS["/var/log"] = "log_t" 66DEFAULT_DIRS["/var/run"] = "var_run_t" 67DEFAULT_DIRS["/run"] = "var_run_t" 68DEFAULT_DIRS["/run/lock"] = "var_lock_t" 69DEFAULT_DIRS["/var/run/lock"] = "var_lock_t" 70DEFAULT_DIRS["/var/spool"] = "var_spool_t" 71DEFAULT_DIRS["/var/www"] = "content_t" 72 73file_type_str = {} 74file_type_str["a"] = _("all files") 75file_type_str["f"] = _("regular file") 76file_type_str["d"] = _("directory") 77file_type_str["c"] = _("character device") 78file_type_str["b"] = _("block device") 79file_type_str["s"] = _("socket file") 80file_type_str["l"] = _("symbolic link") 81file_type_str["p"] = _("named pipe") 82 83trans_file_type_str = {} 84trans_file_type_str[""] = "a" 85trans_file_type_str["--"] = "f" 86trans_file_type_str["-d"] = "d" 87trans_file_type_str["-c"] = "c" 88trans_file_type_str["-b"] = "b" 89trans_file_type_str["-s"] = "s" 90trans_file_type_str["-l"] = "l" 91trans_file_type_str["-p"] = "p" 92 93# the setools policy handle 94_pol = None 95 96# cache the lookup results 97file_equiv_modified = None 98file_equiv = None 99local_files = None 100fcdict = None 101methods = [] 102all_types = None 103all_types_info = None 104user_types = None 105role_allows = None 106portrecs = None 107portrecsbynum = None 108all_domains = None 109roles = None 110selinux_user_list = None 111login_mappings = None 112file_types = None 113port_types = None 114bools = None 115all_attributes = None 116booleans = None 117booleans_dict = None 118all_allow_rules = None 119all_transitions = None 120 121 122def get_installed_policy(root="/"): 123 try: 124 path = root + selinux.selinux_binary_policy_path() 125 policies = glob.glob("%s.*" % path) 126 policies.sort() 127 return policies[-1] 128 except: 129 pass 130 raise ValueError(_("No SELinux Policy installed")) 131 132 133def policy(policy_file): 134 global all_domains 135 global all_attributes 136 global bools 137 global all_types 138 global role_allows 139 global users 140 global roles 141 global file_types 142 global port_types 143 all_domains = None 144 all_attributes = None 145 bools = None 146 all_types = None 147 role_allows = None 148 users = None 149 roles = None 150 file_types = None 151 port_types = None 152 global _pol 153 154 try: 155 _pol = setools.SELinuxPolicy(policy_file) 156 except: 157 raise ValueError(_("Failed to read %s policy file") % policy_file) 158 159 160try: 161 policy_file = get_installed_policy() 162 policy(policy_file) 163except ValueError as e: 164 if selinux.is_selinux_enabled() == 1: 165 raise e 166 167 168def info(setype, name=None): 169 if setype == TYPE: 170 q = setools.TypeQuery(_pol) 171 if name: 172 q.name = name 173 174 return ({ 175 'aliases': list(map(str, x.aliases())), 176 'name': str(x), 177 'permissive': bool(x.ispermissive), 178 'attributes': list(map(str, x.attributes())) 179 } for x in q.results()) 180 181 elif setype == ROLE: 182 q = setools.RoleQuery(_pol) 183 if name: 184 q.name = name 185 186 return ({ 187 'name': str(x), 188 'roles': list(map(str, x.expand())), 189 'types': list(map(str, x.types())), 190 } for x in q.results()) 191 192 elif setype == ATTRIBUTE: 193 q = setools.TypeAttributeQuery(_pol) 194 if name: 195 q.name = name 196 197 return ({ 198 'name': str(x), 199 'types': list(map(str, x.expand())), 200 } for x in q.results()) 201 202 elif setype == PORT: 203 q = setools.PortconQuery(_pol) 204 if name: 205 ports = [int(i) for i in name.split("-")] 206 if len(ports) == 2: 207 q.ports = ports 208 elif len(ports) == 1: 209 q.ports = (ports[0], ports[0]) 210 211 if _pol.mls: 212 return ({ 213 'high': x.ports.high, 214 'protocol': str(x.protocol), 215 'range': str(x.context.range_), 216 'type': str(x.context.type_), 217 'low': x.ports.low, 218 } for x in q.results()) 219 return ({ 220 'high': x.ports.high, 221 'protocol': str(x.protocol), 222 'type': str(x.context.type_), 223 'low': x.ports.low, 224 } for x in q.results()) 225 226 elif setype == USER: 227 q = setools.UserQuery(_pol) 228 if name: 229 q.name = name 230 231 if _pol.mls: 232 return ({ 233 'range': str(x.mls_range), 234 'name': str(x), 235 'roles': list(map(str, x.roles)), 236 'level': str(x.mls_level), 237 } for x in q.results()) 238 return ({ 239 'name': str(x), 240 'roles': list(map(str, x.roles)), 241 } for x in q.results()) 242 243 elif setype == BOOLEAN: 244 q = setools.BoolQuery(_pol) 245 if name: 246 q.name = name 247 248 return ({ 249 'name': str(x), 250 'state': x.state, 251 } for x in q.results()) 252 253 elif setype == TCLASS: 254 q = setools.ObjClassQuery(_pol) 255 if name: 256 q.name = name 257 258 return ({ 259 'name': str(x), 260 'permlist': list(x.perms), 261 } for x in q.results()) 262 263 else: 264 raise ValueError("Invalid type") 265 266 267def _setools_rule_to_dict(rule): 268 d = { 269 'type': str(rule.ruletype), 270 'source': str(rule.source), 271 'target': str(rule.target), 272 'class': str(rule.tclass), 273 } 274 275 try: 276 enabled = bool(rule.qpol_symbol.is_enabled(rule.policy)) 277 except AttributeError: 278 enabled = True 279 280 if isinstance(rule, setools.policyrep.terule.AVRule): 281 d['enabled'] = enabled 282 283 try: 284 d['permlist'] = list(map(str, rule.perms)) 285 except setools.policyrep.exception.RuleUseError: 286 pass 287 288 try: 289 d['transtype'] = str(rule.default) 290 except setools.policyrep.exception.RuleUseError: 291 pass 292 293 try: 294 d['boolean'] = [(str(rule.conditional), enabled)] 295 except (AttributeError, setools.policyrep.exception.RuleNotConditional): 296 pass 297 298 try: 299 d['filename'] = rule.filename 300 except (AttributeError, 301 setools.policyrep.exception.RuleNotConditional, 302 setools.policyrep.exception.TERuleNoFilename): 303 pass 304 305 return d 306 307 308def search(types, seinfo=None): 309 if not seinfo: 310 seinfo = {} 311 valid_types = set([ALLOW, AUDITALLOW, NEVERALLOW, DONTAUDIT, TRANSITION, ROLE_ALLOW]) 312 for setype in types: 313 if setype not in valid_types: 314 raise ValueError("Type has to be in %s" % " ".join(valid_types)) 315 316 source = None 317 if SOURCE in seinfo: 318 source = str(seinfo[SOURCE]) 319 320 target = None 321 if TARGET in seinfo: 322 target = str(seinfo[TARGET]) 323 324 tclass = None 325 if CLASS in seinfo: 326 tclass = str(seinfo[CLASS]).split(',') 327 328 toret = [] 329 330 tertypes = [] 331 if ALLOW in types: 332 tertypes.append(ALLOW) 333 if NEVERALLOW in types: 334 tertypes.append(NEVERALLOW) 335 if AUDITALLOW in types: 336 tertypes.append(AUDITALLOW) 337 338 if len(tertypes) > 0: 339 q = setools.TERuleQuery(_pol, 340 ruletype=tertypes, 341 source=source, 342 target=target, 343 tclass=tclass) 344 345 if PERMS in seinfo: 346 q.perms = seinfo[PERMS] 347 348 toret += [_setools_rule_to_dict(x) for x in q.results()] 349 350 if TRANSITION in types: 351 rtypes = ['type_transition', 'type_change', 'type_member'] 352 q = setools.TERuleQuery(_pol, 353 ruletype=rtypes, 354 source=source, 355 target=target, 356 tclass=tclass) 357 358 if PERMS in seinfo: 359 q.perms = seinfo[PERMS] 360 361 toret += [_setools_rule_to_dict(x) for x in q.results()] 362 363 if ROLE_ALLOW in types: 364 ratypes = ['allow'] 365 q = setools.RBACRuleQuery(_pol, 366 ruletype=ratypes, 367 source=source, 368 target=target, 369 tclass=tclass) 370 371 for r in q.results(): 372 toret.append({'source': str(r.source), 373 'target': str(r.target)}) 374 375 return toret 376 377 378def get_conditionals(src, dest, tclass, perm): 379 tdict = {} 380 tlist = [] 381 src_list = [src] 382 dest_list = [dest] 383 # add assigned attributes 384 try: 385 src_list += list(filter(lambda x: x['name'] == src, get_all_types_info()))[0]['attributes'] 386 except: 387 pass 388 try: 389 dest_list += list(filter(lambda x: x['name'] == dest, get_all_types_info()))[0]['attributes'] 390 except: 391 pass 392 allows = map(lambda y: y, filter(lambda x: 393 x['source'] in src_list and 394 x['target'] in dest_list and 395 set(perm).issubset(x[PERMS]) and 396 'boolean' in x, 397 get_all_allow_rules())) 398 399 try: 400 for i in allows: 401 tdict.update({'source': i['source'], 'boolean': i['boolean']}) 402 if tdict not in tlist: 403 tlist.append(tdict) 404 tdict = {} 405 except KeyError: 406 return(tlist) 407 408 return (tlist) 409 410 411def get_conditionals_format_text(cond): 412 413 enabled = False 414 for x in cond: 415 if x['boolean'][0][1]: 416 enabled = True 417 break 418 return _("-- Allowed %s [ %s ]") % (enabled, " || ".join(set(map(lambda x: "%s=%d" % (x['boolean'][0][0], x['boolean'][0][1]), cond)))) 419 420 421def get_types_from_attribute(attribute): 422 return list(info(ATTRIBUTE, attribute))[0]["types"] 423 424 425def get_file_types(setype): 426 flist = [] 427 mpaths = {} 428 for f in get_all_file_types(): 429 if f.startswith(gen_short_name(setype)): 430 flist.append(f) 431 fcdict = get_fcdict() 432 for f in flist: 433 try: 434 mpaths[f] = (fcdict[f]["regex"], file_type_str[fcdict[f]["ftype"]]) 435 except KeyError: 436 mpaths[f] = [] 437 return mpaths 438 439 440def get_writable_files(setype): 441 file_types = get_all_file_types() 442 all_writes = [] 443 mpaths = {} 444 permlist = search([ALLOW], {'source': setype, 'permlist': ['open', 'write'], 'class': 'file'}) 445 if permlist is None or len(permlist) == 0: 446 return mpaths 447 448 fcdict = get_fcdict() 449 450 attributes = ["proc_type", "sysctl_type"] 451 for i in permlist: 452 if i['target'] in attributes: 453 continue 454 if "enabled" in i: 455 if not i["enabled"]: 456 continue 457 if i['target'].endswith("_t"): 458 if i['target'] not in file_types: 459 continue 460 if i['target'] not in all_writes: 461 if i['target'] != setype: 462 all_writes.append(i['target']) 463 else: 464 for t in get_types_from_attribute(i['target']): 465 if t not in all_writes: 466 all_writes.append(t) 467 468 for f in all_writes: 469 try: 470 mpaths[f] = (fcdict[f]["regex"], file_type_str[fcdict[f]["ftype"]]) 471 except KeyError: 472 mpaths[f] = [] # {"regex":[],"paths":[]} 473 return mpaths 474 475 476def find_file(reg): 477 if os.path.exists(reg): 478 return [reg] 479 try: 480 pat = re.compile(r"%s$" % reg) 481 except: 482 print("bad reg:", reg) 483 return [] 484 p = reg 485 if p.endswith("(/.*)?"): 486 p = p[:-6] + "/" 487 488 path = os.path.dirname(p) 489 490 try: # Bug fix: when "all files on system" 491 if path[-1] != "/": # is pass in it breaks without try block 492 path += "/" 493 except IndexError: 494 print("try failed got an IndexError") 495 pass 496 497 try: 498 pat = re.compile(r"%s$" % reg) 499 return [x for x in map(lambda x: path + x, os.listdir(path)) if pat.match(x)] 500 except: 501 return [] 502 503 504def find_all_files(domain, exclude_list=[]): 505 executable_files = get_entrypoints(domain) 506 for exe in executable_files.keys(): 507 if exe.endswith("_exec_t") and exe not in exclude_list: 508 for path in executable_files[exe]: 509 for f in find_file(path): 510 return f 511 return None 512 513 514def find_entrypoint_path(exe, exclude_list=[]): 515 fcdict = get_fcdict() 516 try: 517 if exe.endswith("_exec_t") and exe not in exclude_list: 518 for path in fcdict[exe]["regex"]: 519 for f in find_file(path): 520 return f 521 except KeyError: 522 pass 523 return None 524 525 526def read_file_equiv(edict, fc_path, modify): 527 try: 528 with open(fc_path, "r") as fd: 529 for e in fd: 530 f = e.split() 531 if f and not f[0].startswith('#'): 532 edict[f[0]] = {"equiv": f[1], "modify": modify} 533 except OSError as e: 534 if e.errno != errno.ENOENT: 535 raise 536 return edict 537 538 539def get_file_equiv_modified(fc_path=selinux.selinux_file_context_path()): 540 global file_equiv_modified 541 if file_equiv_modified: 542 return file_equiv_modified 543 file_equiv_modified = {} 544 file_equiv_modified = read_file_equiv(file_equiv_modified, fc_path + ".subs", modify=True) 545 return file_equiv_modified 546 547 548def get_file_equiv(fc_path=selinux.selinux_file_context_path()): 549 global file_equiv 550 if file_equiv: 551 return file_equiv 552 file_equiv = get_file_equiv_modified(fc_path) 553 file_equiv = read_file_equiv(file_equiv, fc_path + ".subs_dist", modify=False) 554 return file_equiv 555 556 557def get_local_file_paths(fc_path=selinux.selinux_file_context_path()): 558 global local_files 559 if local_files: 560 return local_files 561 local_files = [] 562 try: 563 with open(fc_path + ".local", "r") as fd: 564 fc = fd.readlines() 565 except OSError as e: 566 if e.errno != errno.ENOENT: 567 raise 568 return [] 569 for i in fc: 570 rec = i.split() 571 if len(rec) == 0: 572 continue 573 try: 574 if len(rec) > 2: 575 ftype = trans_file_type_str[rec[1]] 576 else: 577 ftype = "a" 578 579 local_files.append((rec[0], ftype)) 580 except KeyError: 581 pass 582 return local_files 583 584 585def get_fcdict(fc_path=selinux.selinux_file_context_path()): 586 global fcdict 587 if fcdict: 588 return fcdict 589 fd = open(fc_path, "r") 590 fc = fd.readlines() 591 fd.close() 592 fd = open(fc_path + ".homedirs", "r") 593 fc += fd.readlines() 594 fd.close() 595 fcdict = {} 596 try: 597 with open(fc_path + ".local", "r") as fd: 598 fc += fd.readlines() 599 except OSError as e: 600 if e.errno != errno.ENOENT: 601 raise 602 603 for i in fc: 604 rec = i.split() 605 try: 606 if len(rec) > 2: 607 ftype = trans_file_type_str[rec[1]] 608 else: 609 ftype = "a" 610 611 t = rec[-1].split(":")[2] 612 if t in fcdict: 613 fcdict[t]["regex"].append(rec[0]) 614 else: 615 fcdict[t] = {"regex": [rec[0]], "ftype": ftype} 616 except: 617 pass 618 619 fcdict["logfile"] = {"regex": ["all log files"]} 620 fcdict["user_tmp_type"] = {"regex": ["all user tmp files"]} 621 fcdict["user_home_type"] = {"regex": ["all user home files"]} 622 fcdict["virt_image_type"] = {"regex": ["all virtual image files"]} 623 fcdict["noxattrfs"] = {"regex": ["all files on file systems which do not support extended attributes"]} 624 fcdict["sandbox_tmpfs_type"] = {"regex": ["all sandbox content in tmpfs file systems"]} 625 fcdict["user_tmpfs_type"] = {"regex": ["all user content in tmpfs file systems"]} 626 fcdict["file_type"] = {"regex": ["all files on the system"]} 627 fcdict["samba_share_t"] = {"regex": ["use this label for random content that will be shared using samba"]} 628 return fcdict 629 630 631def get_transitions_into(setype): 632 try: 633 return [x for x in search([TRANSITION], {'class': 'process'}) if x["transtype"] == setype] 634 except (TypeError, AttributeError): 635 pass 636 return None 637 638 639def get_transitions(setype): 640 try: 641 return search([TRANSITION], {'source': setype, 'class': 'process'}) 642 except (TypeError, AttributeError): 643 pass 644 return None 645 646 647def get_file_transitions(setype): 648 try: 649 return [x for x in search([TRANSITION], {'source': setype}) if x['class'] != "process"] 650 except (TypeError, AttributeError): 651 pass 652 return None 653 654 655def get_boolean_rules(setype, boolean): 656 boollist = [] 657 permlist = search([ALLOW], {'source': setype}) 658 for p in permlist: 659 if "boolean" in p: 660 try: 661 for b in p["boolean"]: 662 if boolean in b: 663 boollist.append(p) 664 except: 665 pass 666 return boollist 667 668 669def get_all_entrypoints(): 670 return get_types_from_attribute("entry_type") 671 672 673def get_entrypoint_types(setype): 674 q = setools.TERuleQuery(_pol, 675 ruletype=[ALLOW], 676 source=setype, 677 tclass=["file"], 678 perms=["entrypoint"]) 679 return [str(x.target) for x in q.results() if x.source == setype] 680 681 682def get_init_transtype(path): 683 entrypoint = selinux.getfilecon(path)[1].split(":")[2] 684 try: 685 entrypoints = list(filter(lambda x: x['target'] == entrypoint, search([TRANSITION], {'source': "init_t", 'class': 'process'}))) 686 return entrypoints[0]["transtype"] 687 except (TypeError, AttributeError, IndexError): 688 pass 689 return None 690 691 692def get_init_entrypoint(transtype): 693 q = setools.TERuleQuery(_pol, 694 ruletype=["type_transition"], 695 source="init_t", 696 tclass=["process"]) 697 entrypoints = [] 698 for i in q.results(): 699 try: 700 if i.default == transtype: 701 entrypoints.append(i.target) 702 except AttributeError: 703 continue 704 705 return entrypoints 706 707def get_init_entrypoints_str(): 708 q = setools.TERuleQuery(_pol, 709 ruletype=["type_transition"], 710 source="init_t", 711 tclass=["process"]) 712 entrypoints = {} 713 for i in q.results(): 714 try: 715 transtype = str(i.default) 716 if transtype in entrypoints: 717 entrypoints[transtype].append(str(i.target)) 718 else: 719 entrypoints[transtype] = [str(i.target)] 720 except AttributeError: 721 continue 722 723 return entrypoints 724 725def get_init_entrypoint_target(entrypoint): 726 try: 727 entrypoints = map(lambda x: x['transtype'], search([TRANSITION], {'source': "init_t", 'target': entrypoint, 'class': 'process'})) 728 return list(entrypoints)[0] 729 except (TypeError, IndexError): 730 pass 731 return None 732 733 734def get_entrypoints(setype): 735 fcdict = get_fcdict() 736 mpaths = {} 737 for f in get_entrypoint_types(setype): 738 try: 739 mpaths[f] = (fcdict[f]["regex"], file_type_str[fcdict[f]["ftype"]]) 740 except KeyError: 741 mpaths[f] = [] 742 return mpaths 743 744 745def get_methods(): 746 global methods 747 if len(methods) > 0: 748 return methods 749 gen_interfaces() 750 fn = defaults.interface_info() 751 try: 752 fd = open(fn) 753 # List of per_role_template interfaces 754 ifs = interfaces.InterfaceSet() 755 ifs.from_file(fd) 756 methods = list(ifs.interfaces.keys()) 757 fd.close() 758 except: 759 sys.stderr.write("could not open interface info [%s]\n" % fn) 760 sys.exit(1) 761 762 methods.sort() 763 return methods 764 765 766def get_all_types(): 767 global all_types 768 if all_types is None: 769 all_types = [x['name'] for x in info(TYPE)] 770 return all_types 771 772def get_all_types_info(): 773 global all_types_info 774 if all_types_info is None: 775 all_types_info = list(info(TYPE)) 776 return all_types_info 777 778def get_user_types(): 779 global user_types 780 if user_types is None: 781 user_types = list(list(info(ATTRIBUTE, "userdomain"))[0]["types"]) 782 return user_types 783 784 785def get_all_role_allows(): 786 global role_allows 787 if role_allows: 788 return role_allows 789 role_allows = {} 790 791 q = setools.RBACRuleQuery(_pol, ruletype=[ALLOW]) 792 for r in q.results(): 793 src = str(r.source) 794 tgt = str(r.target) 795 if src == "system_r" or tgt == "system_r": 796 continue 797 if src in role_allows: 798 role_allows[src].append(tgt) 799 else: 800 role_allows[src] = [tgt] 801 802 return role_allows 803 804 805def get_all_entrypoint_domains(): 806 import re 807 all_domains = [] 808 types = sorted(get_all_types()) 809 for i in types: 810 m = re.findall("(.*)%s" % "_exec_t$", i) 811 if len(m) > 0: 812 if len(re.findall("(.*)%s" % "_initrc$", m[0])) == 0 and m[0] not in all_domains: 813 all_domains.append(m[0]) 814 return all_domains 815 816 817def gen_interfaces(): 818 try: 819 from commands import getstatusoutput 820 except ImportError: 821 from subprocess import getstatusoutput 822 ifile = defaults.interface_info() 823 headers = defaults.headers() 824 try: 825 if os.stat(headers).st_mtime <= os.stat(ifile).st_mtime: 826 return 827 except OSError: 828 pass 829 830 if os.getuid() != 0: 831 raise ValueError(_("You must regenerate interface info by running /usr/bin/sepolgen-ifgen")) 832 print(getstatusoutput("/usr/bin/sepolgen-ifgen")[1]) 833 834 835def gen_port_dict(): 836 global portrecs 837 global portrecsbynum 838 if portrecs: 839 return (portrecs, portrecsbynum) 840 portrecsbynum = {} 841 portrecs = {} 842 for i in info(PORT): 843 if i['low'] == i['high']: 844 port = str(i['low']) 845 else: 846 port = "%s-%s" % (str(i['low']), str(i['high'])) 847 848 if (i['type'], i['protocol']) in portrecs: 849 portrecs[(i['type'], i['protocol'])].append(port) 850 else: 851 portrecs[(i['type'], i['protocol'])] = [port] 852 853 if 'range' in i: 854 portrecsbynum[(i['low'], i['high'], i['protocol'])] = (i['type'], i['range']) 855 else: 856 portrecsbynum[(i['low'], i['high'], i['protocol'])] = (i['type']) 857 858 return (portrecs, portrecsbynum) 859 860 861def get_all_domains(): 862 global all_domains 863 if not all_domains: 864 all_domains = list(list(info(ATTRIBUTE, "domain"))[0]["types"]) 865 return all_domains 866 867 868def get_all_roles(): 869 global roles 870 if roles: 871 return roles 872 873 q = setools.RoleQuery(_pol) 874 roles = [str(x) for x in q.results() if str(x) != "object_r"] 875 return roles 876 877 878def get_selinux_users(): 879 global selinux_user_list 880 if not selinux_user_list: 881 selinux_user_list = list(info(USER)) 882 if _pol.mls: 883 for x in selinux_user_list: 884 x['range'] = "".join(x['range'].split(" ")) 885 return selinux_user_list 886 887 888def get_login_mappings(): 889 global login_mappings 890 if login_mappings: 891 return login_mappings 892 893 fd = open(selinux.selinux_usersconf_path(), "r") 894 buf = fd.read() 895 fd.close() 896 login_mappings = [] 897 for b in buf.split("\n"): 898 b = b.strip() 899 if len(b) == 0 or b.startswith("#"): 900 continue 901 x = b.split(":") 902 login_mappings.append({"name": x[0], "seuser": x[1], "mls": ":".join(x[2:])}) 903 return login_mappings 904 905 906def get_all_users(): 907 return sorted(map(lambda x: x['name'], get_selinux_users())) 908 909 910def get_all_file_types(): 911 global file_types 912 if file_types: 913 return file_types 914 file_types = list(sorted(info(ATTRIBUTE, "file_type"))[0]["types"]) 915 return file_types 916 917 918def get_all_port_types(): 919 global port_types 920 if port_types: 921 return port_types 922 port_types = list(sorted(info(ATTRIBUTE, "port_type"))[0]["types"]) 923 return port_types 924 925 926def get_all_bools(): 927 global bools 928 if not bools: 929 bools = list(info(BOOLEAN)) 930 return bools 931 932 933def prettyprint(f, trim): 934 return " ".join(f[:-len(trim)].split("_")) 935 936 937def markup(f): 938 return f 939 940 941def get_description(f, markup=markup): 942 943 txt = "Set files with the %s type, if you want to " % markup(f) 944 945 if f.endswith("_var_run_t"): 946 return txt + "store the %s files under the /run or /var/run directory." % prettyprint(f, "_var_run_t") 947 if f.endswith("_pid_t"): 948 return txt + "store the %s files under the /run directory." % prettyprint(f, "_pid_t") 949 if f.endswith("_var_lib_t"): 950 return txt + "store the %s files under the /var/lib directory." % prettyprint(f, "_var_lib_t") 951 if f.endswith("_var_t"): 952 return txt + "store the %s files under the /var directory." % prettyprint(f, "_var_lib_t") 953 if f.endswith("_var_spool_t"): 954 return txt + "store the %s files under the /var/spool directory." % prettyprint(f, "_spool_t") 955 if f.endswith("_spool_t"): 956 return txt + "store the %s files under the /var/spool directory." % prettyprint(f, "_spool_t") 957 if f.endswith("_cache_t") or f.endswith("_var_cache_t"): 958 return txt + "store the files under the /var/cache directory." 959 if f.endswith("_keytab_t"): 960 return txt + "treat the files as kerberos keytab files." 961 if f.endswith("_lock_t"): 962 return txt + "treat the files as %s lock data, stored under the /var/lock directory" % prettyprint(f, "_lock_t") 963 if f.endswith("_log_t"): 964 return txt + "treat the data as %s log data, usually stored under the /var/log directory." % prettyprint(f, "_log_t") 965 if f.endswith("_config_t"): 966 return txt + "treat the files as %s configuration data, usually stored under the /etc directory." % prettyprint(f, "_config_t") 967 if f.endswith("_conf_t"): 968 return txt + "treat the files as %s configuration data, usually stored under the /etc directory." % prettyprint(f, "_conf_t") 969 if f.endswith("_exec_t"): 970 return txt + "transition an executable to the %s_t domain." % f[:-len("_exec_t")] 971 if f.endswith("_cgi_content_t"): 972 return txt + "treat the files as %s cgi content." % prettyprint(f, "_cgi_content_t") 973 if f.endswith("_rw_content_t"): 974 return txt + "treat the files as %s read/write content." % prettyprint(f, "_rw_content_t") 975 if f.endswith("_rw_t"): 976 return txt + "treat the files as %s read/write content." % prettyprint(f, "_rw_t") 977 if f.endswith("_write_t"): 978 return txt + "treat the files as %s read/write content." % prettyprint(f, "_write_t") 979 if f.endswith("_db_t"): 980 return txt + "treat the files as %s database content." % prettyprint(f, "_db_t") 981 if f.endswith("_ra_content_t"): 982 return txt + "treat the files as %s read/append content." % prettyprint(f, "_ra_content_t") 983 if f.endswith("_cert_t"): 984 return txt + "treat the files as %s certificate data." % prettyprint(f, "_cert_t") 985 if f.endswith("_key_t"): 986 return txt + "treat the files as %s key data." % prettyprint(f, "_key_t") 987 988 if f.endswith("_secret_t"): 989 return txt + "treat the files as %s secret data." % prettyprint(f, "_key_t") 990 991 if f.endswith("_ra_t"): 992 return txt + "treat the files as %s read/append content." % prettyprint(f, "_ra_t") 993 994 if f.endswith("_ro_t"): 995 return txt + "treat the files as %s read/only content." % prettyprint(f, "_ro_t") 996 997 if f.endswith("_modules_t"): 998 return txt + "treat the files as %s modules." % prettyprint(f, "_modules_t") 999 1000 if f.endswith("_content_t"): 1001 return txt + "treat the files as %s content." % prettyprint(f, "_content_t") 1002 1003 if f.endswith("_state_t"): 1004 return txt + "treat the files as %s state data." % prettyprint(f, "_state_t") 1005 1006 if f.endswith("_files_t"): 1007 return txt + "treat the files as %s content." % prettyprint(f, "_files_t") 1008 1009 if f.endswith("_file_t"): 1010 return txt + "treat the files as %s content." % prettyprint(f, "_file_t") 1011 1012 if f.endswith("_data_t"): 1013 return txt + "treat the files as %s content." % prettyprint(f, "_data_t") 1014 1015 if f.endswith("_file_t"): 1016 return txt + "treat the data as %s content." % prettyprint(f, "_file_t") 1017 1018 if f.endswith("_tmp_t"): 1019 return txt + "store %s temporary files in the /tmp directories." % prettyprint(f, "_tmp_t") 1020 if f.endswith("_etc_t"): 1021 return txt + "store %s files in the /etc directories." % prettyprint(f, "_tmp_t") 1022 if f.endswith("_home_t"): 1023 return txt + "store %s files in the users home directory." % prettyprint(f, "_home_t") 1024 if f.endswith("_tmpfs_t"): 1025 return txt + "store %s files on a tmpfs file system." % prettyprint(f, "_tmpfs_t") 1026 if f.endswith("_unit_file_t"): 1027 return txt + "treat files as a systemd unit file." 1028 if f.endswith("_htaccess_t"): 1029 return txt + "treat the file as a %s access file." % prettyprint(f, "_htaccess_t") 1030 1031 return txt + "treat the files as %s data." % prettyprint(f, "_t") 1032 1033 1034def get_all_attributes(): 1035 global all_attributes 1036 if not all_attributes: 1037 all_attributes = list(sorted(map(lambda x: x['name'], info(ATTRIBUTE)))) 1038 return all_attributes 1039 1040 1041def _dict_has_perms(dict, perms): 1042 for perm in perms: 1043 if perm not in dict[PERMS]: 1044 return False 1045 return True 1046 1047 1048def gen_short_name(setype): 1049 all_domains = get_all_domains() 1050 if setype.endswith("_t"): 1051 domainname = setype[:-2] 1052 else: 1053 domainname = setype 1054 if domainname + "_t" not in all_domains: 1055 raise ValueError("domain %s_t does not exist" % domainname) 1056 if domainname[-1] == 'd': 1057 short_name = domainname[:-1] + "_" 1058 else: 1059 short_name = domainname + "_" 1060 return (domainname, short_name) 1061 1062def get_all_allow_rules(): 1063 global all_allow_rules 1064 if not all_allow_rules: 1065 all_allow_rules = search([ALLOW]) 1066 return all_allow_rules 1067 1068def get_all_transitions(): 1069 global all_transitions 1070 if not all_transitions: 1071 all_transitions = list(search([TRANSITION])) 1072 return all_transitions 1073 1074def get_bools(setype): 1075 bools = [] 1076 domainbools = [] 1077 domainname, short_name = gen_short_name(setype) 1078 for i in map(lambda x: x['boolean'], filter(lambda x: 'boolean' in x and x['source'] == setype, get_all_allow_rules())): 1079 for b in i: 1080 if not isinstance(b, tuple): 1081 continue 1082 try: 1083 enabled = selinux.security_get_boolean_active(b[0]) 1084 except OSError: 1085 enabled = b[1] 1086 if b[0].startswith(short_name) or b[0].startswith(domainname): 1087 if (b[0], enabled) not in domainbools and (b[0], not enabled) not in domainbools: 1088 domainbools.append((b[0], enabled)) 1089 else: 1090 if (b[0], enabled) not in bools and (b[0], not enabled) not in bools: 1091 bools.append((b[0], enabled)) 1092 return (domainbools, bools) 1093 1094 1095def get_all_booleans(): 1096 global booleans 1097 if not booleans: 1098 booleans = selinux.security_get_boolean_names()[1] 1099 return booleans 1100 1101 1102def policy_xml(path="/usr/share/selinux/devel/policy.xml"): 1103 try: 1104 fd = gzip.open(path) 1105 buf = fd.read() 1106 fd.close() 1107 except IOError: 1108 fd = open(path) 1109 buf = fd.read() 1110 fd.close() 1111 return buf 1112 1113 1114def gen_bool_dict(path="/usr/share/selinux/devel/policy.xml"): 1115 global booleans_dict 1116 if booleans_dict: 1117 return booleans_dict 1118 import xml.etree.ElementTree 1119 booleans_dict = {} 1120 try: 1121 tree = xml.etree.ElementTree.fromstring(policy_xml(path)) 1122 for l in tree.findall("layer"): 1123 for m in l.findall("module"): 1124 for b in m.findall("tunable"): 1125 desc = b.find("desc").find("p").text.strip("\n") 1126 desc = re.sub("\n", " ", desc) 1127 booleans_dict[b.get('name')] = (m.get("name"), b.get('dftval'), desc) 1128 for b in m.findall("bool"): 1129 desc = b.find("desc").find("p").text.strip("\n") 1130 desc = re.sub("\n", " ", desc) 1131 booleans_dict[b.get('name')] = (m.get("name"), b.get('dftval'), desc) 1132 for i in tree.findall("bool"): 1133 desc = i.find("desc").find("p").text.strip("\n") 1134 desc = re.sub("\n", " ", desc) 1135 booleans_dict[i.get('name')] = ("global", i.get('dftval'), desc) 1136 for i in tree.findall("tunable"): 1137 desc = i.find("desc").find("p").text.strip("\n") 1138 desc = re.sub("\n", " ", desc) 1139 booleans_dict[i.get('name')] = ("global", i.get('dftval'), desc) 1140 except IOError: 1141 pass 1142 return booleans_dict 1143 1144 1145def boolean_category(boolean): 1146 booleans_dict = gen_bool_dict() 1147 if boolean in booleans_dict: 1148 return _(booleans_dict[boolean][0]) 1149 else: 1150 return _("unknown") 1151 1152 1153def boolean_desc(boolean): 1154 booleans_dict = gen_bool_dict() 1155 if boolean in booleans_dict: 1156 return _(booleans_dict[boolean][2]) 1157 else: 1158 desc = boolean.split("_") 1159 return "Allow %s to %s" % (desc[0], " ".join(desc[1:])) 1160 1161 1162def get_os_version(): 1163 os_version = "" 1164 pkg_name = "selinux-policy" 1165 try: 1166 try: 1167 from commands import getstatusoutput 1168 except ImportError: 1169 from subprocess import getstatusoutput 1170 rc, output = getstatusoutput("rpm -q '%s'" % pkg_name) 1171 if rc == 0: 1172 os_version = output.split(".")[-2] 1173 except: 1174 os_version = "" 1175 1176 if os_version[0:2] == "fc": 1177 os_version = "Fedora" + os_version[2:] 1178 elif os_version[0:2] == "el": 1179 os_version = "RHEL" + os_version[2:] 1180 else: 1181 os_version = "" 1182 1183 return os_version 1184 1185 1186def reinit(): 1187 global all_attributes 1188 global all_domains 1189 global all_types 1190 global booleans 1191 global booleans_dict 1192 global bools 1193 global fcdict 1194 global file_types 1195 global local_files 1196 global methods 1197 global methods 1198 global portrecs 1199 global portrecsbynum 1200 global port_types 1201 global role_allows 1202 global roles 1203 global login_mappings 1204 global selinux_user_list 1205 global user_types 1206 all_attributes = None 1207 all_domains = None 1208 all_types = None 1209 booleans = None 1210 booleans_dict = None 1211 bools = None 1212 fcdict = None 1213 file_types = None 1214 local_files = None 1215 methods = None 1216 methods = None 1217 portrecs = None 1218 portrecsbynum = None 1219 port_types = None 1220 role_allows = None 1221 roles = None 1222 user_types = None 1223 login_mappings = None 1224 selinux_user_list = None 1225