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