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 543 try: 544 pat = re.compile(r"%s$" % reg) 545 return [x for x in map(lambda x: path + x, os.listdir(path)) if pat.match(x)] 546 except: 547 return [] 548 549 550def find_all_files(domain, exclude_list=[]): 551 executable_files = get_entrypoints(domain) 552 for exe in executable_files.keys(): 553 if exe.endswith("_exec_t") and exe not in exclude_list: 554 for path in executable_files[exe]: 555 for f in find_file(path): 556 return f 557 return None 558 559 560def find_entrypoint_path(exe, exclude_list=[]): 561 fcdict = get_fcdict() 562 try: 563 if exe.endswith("_exec_t") and exe not in exclude_list: 564 for path in fcdict[exe]["regex"]: 565 for f in find_file(path): 566 return f 567 except KeyError: 568 pass 569 return None 570 571 572def read_file_equiv(edict, fc_path, modify): 573 try: 574 with open(fc_path, "r") as fd: 575 for e in fd: 576 f = e.split() 577 if f and not f[0].startswith('#'): 578 edict[f[0]] = {"equiv": f[1], "modify": modify} 579 except OSError as e: 580 if e.errno != errno.ENOENT: 581 raise 582 return edict 583 584 585def get_file_equiv_modified(fc_path=selinux.selinux_file_context_path()): 586 global file_equiv_modified 587 if file_equiv_modified: 588 return file_equiv_modified 589 file_equiv_modified = {} 590 file_equiv_modified = read_file_equiv(file_equiv_modified, fc_path + ".subs", modify=True) 591 return file_equiv_modified 592 593 594def get_file_equiv(fc_path=selinux.selinux_file_context_path()): 595 global file_equiv 596 if file_equiv: 597 return file_equiv 598 file_equiv = get_file_equiv_modified(fc_path) 599 file_equiv = read_file_equiv(file_equiv, fc_path + ".subs_dist", modify=False) 600 return file_equiv 601 602 603def get_local_file_paths(fc_path=selinux.selinux_file_context_path()): 604 global local_files 605 if local_files: 606 return local_files 607 local_files = [] 608 try: 609 with open(fc_path + ".local", "r") as fd: 610 fc = fd.readlines() 611 except OSError as e: 612 if e.errno != errno.ENOENT: 613 raise 614 return [] 615 for i in fc: 616 rec = i.split() 617 if len(rec) == 0: 618 continue 619 try: 620 if len(rec) > 2: 621 ftype = trans_file_type_str[rec[1]] 622 else: 623 ftype = "a" 624 625 local_files.append((rec[0], ftype)) 626 except KeyError: 627 pass 628 return local_files 629 630 631def get_fcdict(fc_path=selinux.selinux_file_context_path()): 632 global fcdict 633 if fcdict: 634 return fcdict 635 fd = open(fc_path, "r") 636 fc = fd.readlines() 637 fd.close() 638 fd = open(fc_path + ".homedirs", "r") 639 fc += fd.readlines() 640 fd.close() 641 fcdict = {} 642 try: 643 with open(fc_path + ".local", "r") as fd: 644 fc += fd.readlines() 645 except OSError as e: 646 if e.errno != errno.ENOENT: 647 raise 648 649 for i in fc: 650 rec = i.split() 651 try: 652 if len(rec) > 2: 653 ftype = trans_file_type_str[rec[1]] 654 else: 655 ftype = "a" 656 657 t = rec[-1].split(":")[2] 658 if t in fcdict: 659 fcdict[t]["regex"].append(rec[0]) 660 else: 661 fcdict[t] = {"regex": [rec[0]], "ftype": ftype} 662 except: 663 pass 664 665 fcdict["logfile"] = {"regex": ["all log files"]} 666 fcdict["user_tmp_type"] = {"regex": ["all user tmp files"]} 667 fcdict["user_home_type"] = {"regex": ["all user home files"]} 668 fcdict["virt_image_type"] = {"regex": ["all virtual image files"]} 669 fcdict["noxattrfs"] = {"regex": ["all files on file systems which do not support extended attributes"]} 670 fcdict["sandbox_tmpfs_type"] = {"regex": ["all sandbox content in tmpfs file systems"]} 671 fcdict["user_tmpfs_type"] = {"regex": ["all user content in tmpfs file systems"]} 672 fcdict["file_type"] = {"regex": ["all files on the system"]} 673 fcdict["samba_share_t"] = {"regex": ["use this label for random content that will be shared using samba"]} 674 return fcdict 675 676 677def get_transitions_into(setype): 678 try: 679 return [x for x in search([TRANSITION], {'class': 'process'}) if x["transtype"] == setype] 680 except (TypeError, AttributeError): 681 pass 682 return None 683 684 685def get_transitions(setype): 686 try: 687 return search([TRANSITION], {'source': setype, 'class': 'process'}) 688 except (TypeError, AttributeError): 689 pass 690 return None 691 692 693def get_file_transitions(setype): 694 try: 695 return [x for x in search([TRANSITION], {'source': setype}) if x['class'] != "process"] 696 except (TypeError, AttributeError): 697 pass 698 return None 699 700 701def get_boolean_rules(setype, boolean): 702 boollist = [] 703 permlist = search([ALLOW], {'source': setype}) 704 for p in permlist: 705 if "boolean" in p: 706 try: 707 for b in p["boolean"]: 708 if boolean in b: 709 boollist.append(p) 710 except: 711 pass 712 return boollist 713 714 715def get_all_entrypoints(): 716 return get_types_from_attribute("entry_type") 717 718 719def get_entrypoint_types(setype): 720 q = setools.TERuleQuery(_pol, 721 ruletype=[ALLOW], 722 source=setype, 723 tclass=["file"], 724 perms=["entrypoint"]) 725 return [str(x.target) for x in q.results() if x.source == setype] 726 727 728def get_init_transtype(path): 729 entrypoint = selinux.getfilecon(path)[1].split(":")[2] 730 try: 731 entrypoints = list(filter(lambda x: x['target'] == entrypoint, search([TRANSITION], {'source': "init_t", 'class': 'process'}))) 732 return entrypoints[0]["transtype"] 733 except (TypeError, AttributeError, IndexError): 734 pass 735 return None 736 737 738def get_init_entrypoint(transtype): 739 q = setools.TERuleQuery(_pol, 740 ruletype=["type_transition"], 741 source="init_t", 742 tclass=["process"]) 743 entrypoints = [] 744 for i in q.results(): 745 try: 746 if i.default == transtype: 747 entrypoints.append(i.target) 748 except AttributeError: 749 continue 750 751 return entrypoints 752 753def get_init_entrypoints_str(): 754 q = setools.TERuleQuery(_pol, 755 ruletype=["type_transition"], 756 source="init_t", 757 tclass=["process"]) 758 entrypoints = {} 759 for i in q.results(): 760 try: 761 transtype = str(i.default) 762 if transtype in entrypoints: 763 entrypoints[transtype].append(str(i.target)) 764 else: 765 entrypoints[transtype] = [str(i.target)] 766 except AttributeError: 767 continue 768 769 return entrypoints 770 771def get_init_entrypoint_target(entrypoint): 772 try: 773 entrypoints = map(lambda x: x['transtype'], search([TRANSITION], {'source': "init_t", 'target': entrypoint, 'class': 'process'})) 774 return list(entrypoints)[0] 775 except (TypeError, IndexError): 776 pass 777 return None 778 779 780def get_entrypoints(setype): 781 fcdict = get_fcdict() 782 mpaths = {} 783 for f in get_entrypoint_types(setype): 784 try: 785 mpaths[f] = (fcdict[f]["regex"], file_type_str[fcdict[f]["ftype"]]) 786 except KeyError: 787 mpaths[f] = [] 788 return mpaths 789 790 791def get_methods(): 792 global methods 793 if len(methods) > 0: 794 return methods 795 gen_interfaces() 796 fn = defaults.interface_info() 797 try: 798 fd = open(fn) 799 # List of per_role_template interfaces 800 ifs = interfaces.InterfaceSet() 801 ifs.from_file(fd) 802 methods = list(ifs.interfaces.keys()) 803 fd.close() 804 except: 805 sys.stderr.write("could not open interface info [%s]\n" % fn) 806 sys.exit(1) 807 808 methods.sort() 809 return methods 810 811 812def get_all_types(): 813 global all_types 814 if all_types is None: 815 all_types = [x['name'] for x in info(TYPE)] 816 return all_types 817 818def get_all_types_info(): 819 global all_types_info 820 if all_types_info is None: 821 all_types_info = list(info(TYPE)) 822 return all_types_info 823 824def get_user_types(): 825 global user_types 826 if user_types is None: 827 user_types = list(list(info(ATTRIBUTE, "userdomain"))[0]["types"]) 828 return user_types 829 830 831def get_all_role_allows(): 832 global role_allows 833 if role_allows: 834 return role_allows 835 role_allows = {} 836 837 q = setools.RBACRuleQuery(_pol, ruletype=[ALLOW]) 838 for r in q.results(): 839 src = str(r.source) 840 tgt = str(r.target) 841 if src == "system_r" or tgt == "system_r": 842 continue 843 if src in role_allows: 844 role_allows[src].append(tgt) 845 else: 846 role_allows[src] = [tgt] 847 848 return role_allows 849 850 851def get_all_entrypoint_domains(): 852 import re 853 all_domains = [] 854 types = sorted(get_all_types()) 855 for i in types: 856 m = re.findall("(.*)%s" % "_exec_t$", i) 857 if len(m) > 0: 858 if len(re.findall("(.*)%s" % "_initrc$", m[0])) == 0 and m[0] not in all_domains: 859 all_domains.append(m[0]) 860 return all_domains 861 862 863def gen_interfaces(): 864 try: 865 from commands import getstatusoutput 866 except ImportError: 867 from subprocess import getstatusoutput 868 ifile = defaults.interface_info() 869 headers = defaults.headers() 870 try: 871 if os.stat(headers).st_mtime <= os.stat(ifile).st_mtime: 872 return 873 except OSError: 874 pass 875 876 if os.getuid() != 0: 877 raise ValueError(_("You must regenerate interface info by running /usr/bin/sepolgen-ifgen")) 878 print(getstatusoutput("/usr/bin/sepolgen-ifgen")[1]) 879 880 881def gen_port_dict(): 882 global portrecs 883 global portrecsbynum 884 if portrecs: 885 return (portrecs, portrecsbynum) 886 portrecsbynum = {} 887 portrecs = {} 888 for i in info(PORT): 889 if i['low'] == i['high']: 890 port = str(i['low']) 891 else: 892 port = "%s-%s" % (str(i['low']), str(i['high'])) 893 894 if (i['type'], i['protocol']) in portrecs: 895 portrecs[(i['type'], i['protocol'])].append(port) 896 else: 897 portrecs[(i['type'], i['protocol'])] = [port] 898 899 if 'range' in i: 900 portrecsbynum[(i['low'], i['high'], i['protocol'])] = (i['type'], i['range']) 901 else: 902 portrecsbynum[(i['low'], i['high'], i['protocol'])] = (i['type']) 903 904 return (portrecs, portrecsbynum) 905 906 907def get_all_domains(): 908 global all_domains 909 if not all_domains: 910 all_domains = list(list(info(ATTRIBUTE, "domain"))[0]["types"]) 911 return all_domains 912 913 914def get_all_roles(): 915 global roles 916 if roles: 917 return roles 918 919 q = setools.RoleQuery(_pol) 920 roles = [str(x) for x in q.results() if str(x) != "object_r"] 921 return roles 922 923 924def get_selinux_users(): 925 global selinux_user_list 926 if not selinux_user_list: 927 selinux_user_list = list(info(USER)) 928 if _pol.mls: 929 for x in selinux_user_list: 930 x['range'] = "".join(x['range'].split(" ")) 931 return selinux_user_list 932 933 934def get_login_mappings(): 935 global login_mappings 936 if login_mappings: 937 return login_mappings 938 939 fd = open(selinux.selinux_usersconf_path(), "r") 940 buf = fd.read() 941 fd.close() 942 login_mappings = [] 943 for b in buf.split("\n"): 944 b = b.strip() 945 if len(b) == 0 or b.startswith("#"): 946 continue 947 x = b.split(":") 948 login_mappings.append({"name": x[0], "seuser": x[1], "mls": ":".join(x[2:])}) 949 return login_mappings 950 951 952def get_all_users(): 953 return sorted(map(lambda x: x['name'], get_selinux_users())) 954 955 956def get_all_file_types(): 957 global file_types 958 if file_types: 959 return file_types 960 file_types = list(sorted(info(ATTRIBUTE, "file_type"))[0]["types"]) 961 return file_types 962 963 964def get_all_port_types(): 965 global port_types 966 if port_types: 967 return port_types 968 port_types = list(sorted(info(ATTRIBUTE, "port_type"))[0]["types"]) 969 return port_types 970 971 972def get_all_bools(): 973 global bools 974 if not bools: 975 bools = list(info(BOOLEAN)) 976 return bools 977 978 979def prettyprint(f, trim): 980 return " ".join(f[:-len(trim)].split("_")) 981 982 983def markup(f): 984 return f 985 986 987def get_description(f, markup=markup): 988 989 txt = "Set files with the %s type, if you want to " % markup(f) 990 991 if f.endswith("_var_run_t"): 992 return txt + "store the %s files under the /run or /var/run directory." % prettyprint(f, "_var_run_t") 993 if f.endswith("_pid_t"): 994 return txt + "store the %s files under the /run directory." % prettyprint(f, "_pid_t") 995 if f.endswith("_var_lib_t"): 996 return txt + "store the %s files under the /var/lib directory." % prettyprint(f, "_var_lib_t") 997 if f.endswith("_var_t"): 998 return txt + "store the %s files under the /var directory." % prettyprint(f, "_var_lib_t") 999 if f.endswith("_var_spool_t"): 1000 return txt + "store the %s files under the /var/spool directory." % prettyprint(f, "_spool_t") 1001 if f.endswith("_spool_t"): 1002 return txt + "store the %s files under the /var/spool directory." % prettyprint(f, "_spool_t") 1003 if f.endswith("_cache_t") or f.endswith("_var_cache_t"): 1004 return txt + "store the files under the /var/cache directory." 1005 if f.endswith("_keytab_t"): 1006 return txt + "treat the files as kerberos keytab files." 1007 if f.endswith("_lock_t"): 1008 return txt + "treat the files as %s lock data, stored under the /var/lock directory" % prettyprint(f, "_lock_t") 1009 if f.endswith("_log_t"): 1010 return txt + "treat the data as %s log data, usually stored under the /var/log directory." % prettyprint(f, "_log_t") 1011 if f.endswith("_config_t"): 1012 return txt + "treat the files as %s configuration data, usually stored under the /etc directory." % prettyprint(f, "_config_t") 1013 if f.endswith("_conf_t"): 1014 return txt + "treat the files as %s configuration data, usually stored under the /etc directory." % prettyprint(f, "_conf_t") 1015 if f.endswith("_exec_t"): 1016 return txt + "transition an executable to the %s_t domain." % f[:-len("_exec_t")] 1017 if f.endswith("_cgi_content_t"): 1018 return txt + "treat the files as %s cgi content." % prettyprint(f, "_cgi_content_t") 1019 if f.endswith("_rw_content_t"): 1020 return txt + "treat the files as %s read/write content." % prettyprint(f, "_rw_content_t") 1021 if f.endswith("_rw_t"): 1022 return txt + "treat the files as %s read/write content." % prettyprint(f, "_rw_t") 1023 if f.endswith("_write_t"): 1024 return txt + "treat the files as %s read/write content." % prettyprint(f, "_write_t") 1025 if f.endswith("_db_t"): 1026 return txt + "treat the files as %s database content." % prettyprint(f, "_db_t") 1027 if f.endswith("_ra_content_t"): 1028 return txt + "treat the files as %s read/append content." % prettyprint(f, "_ra_content_t") 1029 if f.endswith("_cert_t"): 1030 return txt + "treat the files as %s certificate data." % prettyprint(f, "_cert_t") 1031 if f.endswith("_key_t"): 1032 return txt + "treat the files as %s key data." % prettyprint(f, "_key_t") 1033 1034 if f.endswith("_secret_t"): 1035 return txt + "treat the files as %s secret data." % prettyprint(f, "_key_t") 1036 1037 if f.endswith("_ra_t"): 1038 return txt + "treat the files as %s read/append content." % prettyprint(f, "_ra_t") 1039 1040 if f.endswith("_ro_t"): 1041 return txt + "treat the files as %s read/only content." % prettyprint(f, "_ro_t") 1042 1043 if f.endswith("_modules_t"): 1044 return txt + "treat the files as %s modules." % prettyprint(f, "_modules_t") 1045 1046 if f.endswith("_content_t"): 1047 return txt + "treat the files as %s content." % prettyprint(f, "_content_t") 1048 1049 if f.endswith("_state_t"): 1050 return txt + "treat the files as %s state data." % prettyprint(f, "_state_t") 1051 1052 if f.endswith("_files_t"): 1053 return txt + "treat the files as %s content." % prettyprint(f, "_files_t") 1054 1055 if f.endswith("_file_t"): 1056 return txt + "treat the files as %s content." % prettyprint(f, "_file_t") 1057 1058 if f.endswith("_data_t"): 1059 return txt + "treat the files as %s content." % prettyprint(f, "_data_t") 1060 1061 if f.endswith("_file_t"): 1062 return txt + "treat the data as %s content." % prettyprint(f, "_file_t") 1063 1064 if f.endswith("_tmp_t"): 1065 return txt + "store %s temporary files in the /tmp directories." % prettyprint(f, "_tmp_t") 1066 if f.endswith("_etc_t"): 1067 return txt + "store %s files in the /etc directories." % prettyprint(f, "_tmp_t") 1068 if f.endswith("_home_t"): 1069 return txt + "store %s files in the users home directory." % prettyprint(f, "_home_t") 1070 if f.endswith("_tmpfs_t"): 1071 return txt + "store %s files on a tmpfs file system." % prettyprint(f, "_tmpfs_t") 1072 if f.endswith("_unit_file_t"): 1073 return txt + "treat files as a systemd unit file." 1074 if f.endswith("_htaccess_t"): 1075 return txt + "treat the file as a %s access file." % prettyprint(f, "_htaccess_t") 1076 1077 return txt + "treat the files as %s data." % prettyprint(f, "_t") 1078 1079 1080def get_all_attributes(): 1081 global all_attributes 1082 if not all_attributes: 1083 all_attributes = list(sorted(map(lambda x: x['name'], info(ATTRIBUTE)))) 1084 return all_attributes 1085 1086 1087def _dict_has_perms(dict, perms): 1088 for perm in perms: 1089 if perm not in dict[PERMS]: 1090 return False 1091 return True 1092 1093 1094def gen_short_name(setype): 1095 all_domains = get_all_domains() 1096 if setype.endswith("_t"): 1097 # replace aliases with corresponding types 1098 setype = get_real_type_name(setype) 1099 domainname = setype[:-2] 1100 else: 1101 domainname = setype 1102 if domainname + "_t" not in all_domains: 1103 raise ValueError("domain %s_t does not exist" % domainname) 1104 if domainname[-1] == 'd': 1105 short_name = domainname[:-1] + "_" 1106 else: 1107 short_name = domainname + "_" 1108 return (domainname, short_name) 1109 1110def get_all_allow_rules(): 1111 global all_allow_rules 1112 if not all_allow_rules: 1113 all_allow_rules = search([ALLOW]) 1114 return all_allow_rules 1115 1116def get_all_transitions(): 1117 global all_transitions 1118 if not all_transitions: 1119 all_transitions = list(search([TRANSITION])) 1120 return all_transitions 1121 1122def get_bools(setype): 1123 bools = [] 1124 domainbools = [] 1125 domainname, short_name = gen_short_name(setype) 1126 for i in map(lambda x: x['boolean'], filter(lambda x: 'boolean' in x and x['source'] == setype, get_all_allow_rules())): 1127 for b in i: 1128 if not isinstance(b, tuple): 1129 continue 1130 try: 1131 enabled = selinux.security_get_boolean_active(b[0]) 1132 except OSError: 1133 enabled = b[1] 1134 if b[0].startswith(short_name) or b[0].startswith(domainname): 1135 if (b[0], enabled) not in domainbools and (b[0], not enabled) not in domainbools: 1136 domainbools.append((b[0], enabled)) 1137 else: 1138 if (b[0], enabled) not in bools and (b[0], not enabled) not in bools: 1139 bools.append((b[0], enabled)) 1140 return (domainbools, bools) 1141 1142 1143def get_all_booleans(): 1144 global booleans 1145 if not booleans: 1146 booleans = selinux.security_get_boolean_names()[1] 1147 return booleans 1148 1149 1150def policy_xml(path="/usr/share/selinux/devel/policy.xml"): 1151 try: 1152 fd = gzip.open(path) 1153 buf = fd.read() 1154 fd.close() 1155 except IOError: 1156 fd = open(path) 1157 buf = fd.read() 1158 fd.close() 1159 return buf 1160 1161 1162def gen_bool_dict(path="/usr/share/selinux/devel/policy.xml"): 1163 global booleans_dict 1164 if booleans_dict: 1165 return booleans_dict 1166 import xml.etree.ElementTree 1167 booleans_dict = {} 1168 try: 1169 tree = xml.etree.ElementTree.fromstring(policy_xml(path)) 1170 for l in tree.findall("layer"): 1171 for m in l.findall("module"): 1172 for b in m.findall("tunable"): 1173 desc = b.find("desc").find("p").text.strip("\n") 1174 desc = re.sub("\n", " ", desc) 1175 booleans_dict[b.get('name')] = (m.get("name"), b.get('dftval'), desc) 1176 for b in m.findall("bool"): 1177 desc = b.find("desc").find("p").text.strip("\n") 1178 desc = re.sub("\n", " ", desc) 1179 booleans_dict[b.get('name')] = (m.get("name"), b.get('dftval'), desc) 1180 for i in tree.findall("bool"): 1181 desc = i.find("desc").find("p").text.strip("\n") 1182 desc = re.sub("\n", " ", desc) 1183 booleans_dict[i.get('name')] = ("global", i.get('dftval'), desc) 1184 for i in tree.findall("tunable"): 1185 desc = i.find("desc").find("p").text.strip("\n") 1186 desc = re.sub("\n", " ", desc) 1187 booleans_dict[i.get('name')] = ("global", i.get('dftval'), desc) 1188 except IOError: 1189 pass 1190 return booleans_dict 1191 1192 1193def boolean_category(boolean): 1194 booleans_dict = gen_bool_dict() 1195 if boolean in booleans_dict: 1196 return _(booleans_dict[boolean][0]) 1197 else: 1198 return _("unknown") 1199 1200 1201def boolean_desc(boolean): 1202 booleans_dict = gen_bool_dict() 1203 if boolean in booleans_dict: 1204 return _(booleans_dict[boolean][2]) 1205 else: 1206 desc = boolean.split("_") 1207 return "Allow %s to %s" % (desc[0], " ".join(desc[1:])) 1208 1209 1210def get_os_version(): 1211 os_version = "" 1212 pkg_name = "selinux-policy" 1213 try: 1214 try: 1215 from commands import getstatusoutput 1216 except ImportError: 1217 from subprocess import getstatusoutput 1218 rc, output = getstatusoutput("rpm -q '%s'" % pkg_name) 1219 if rc == 0: 1220 os_version = output.split(".")[-2] 1221 except: 1222 os_version = "" 1223 1224 if os_version[0:2] == "fc": 1225 os_version = "Fedora" + os_version[2:] 1226 elif os_version[0:2] == "el": 1227 os_version = "RHEL" + os_version[2:] 1228 else: 1229 os_version = "" 1230 1231 return os_version 1232 1233 1234def reinit(): 1235 global all_attributes 1236 global all_domains 1237 global all_types 1238 global booleans 1239 global booleans_dict 1240 global bools 1241 global fcdict 1242 global file_types 1243 global local_files 1244 global methods 1245 global methods 1246 global portrecs 1247 global portrecsbynum 1248 global port_types 1249 global role_allows 1250 global roles 1251 global login_mappings 1252 global selinux_user_list 1253 global user_types 1254 all_attributes = None 1255 all_domains = None 1256 all_types = None 1257 booleans = None 1258 booleans_dict = None 1259 bools = None 1260 fcdict = None 1261 file_types = None 1262 local_files = None 1263 methods = None 1264 methods = None 1265 portrecs = None 1266 portrecsbynum = None 1267 port_types = None 1268 role_allows = None 1269 roles = None 1270 user_types = None 1271 login_mappings = None 1272 selinux_user_list = None 1273