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