• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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