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