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