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