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