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