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