Viewing file: selinuxPage.py (20.63 KB) -rwxr-xr-x Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
# # selinuxPage.py - GUI for SELinux page in system-config-securitylevel # # Brent Fox <bfox@redhat.com> # Dan Walsh <dwalsh@redhat.com> # # Copyright 2004 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # import string import gtk import os import libxml2 import gobject import sys import tempfile
INSTALLPATH='/usr/share/system-config-securitylevel' sys.path.append(INSTALLPATH) rhplPath="/usr/lib/python%d.%d/site-packages/rhpl" % (sys.version_info[0], sys.version_info[1]) if not rhplPath in sys.path: sys.path.append(rhplPath)
rhplPath="/usr/lib64/python%d.%d/site-packages/rhpl" % (sys.version_info[0], sys.version_info[1]) if not rhplPath in sys.path: sys.path.append(rhplPath)
from Conf import * import commands ENFORCING=0 PERMISSIVE=1 DISABLED=2 SELINUXDIR="/etc/selinux/" RELABELFILE="/.autorelabel"
## ## I18N ## from rhpl.translate import _, N_ import rhpl.translate as translate translate.textdomain ("system-config-securitylevel")
class Translation: def __init__(self): self.translation={} fd=open(INSTALLPATH + "/selinux.tbl","r") lines=fd.readlines() fd.close() for i in lines: try: line=i.strip().split("_(\"") key=line[0].strip() category=line[1].split("\"")[0] value=line[2].split("\"")[0] self.translation[key]=(category,value) except: continue
def get_category(self,key): try: return _(self.translation[key][0]) except: return _("Other")
def get_value(self,key): try: return _(self.translation[key][1]) except: return key
class Modifier: def __init__(self,name, on, save): self.on=on self.name=name self.save=save def set(self,value): self.on=value self.save=True def isOn(self): return self.on
class Tunable(Modifier): def __init__(self,name,val, tunableFile, save=False): Modifier.__init__(self, name, val, save) self.tunableFile=tunableFile self.on=val self.save=True
def set(self,value): Modifier.set(self,value) self.tunableFile.setValue(self.name,value) def write(self): self.tunableFile.write() class Boolean(Modifier): def __init__(self,name, val, save=False): Modifier.__init__(self,name, val, save) class Modifiers: def __init__(self,store): self.modifiers={} self.translation=Translation() self.store=store self.store.clear() self.booleanDirty=False self.tunableDirty=False
def add(self,name,val): if name == "targeted_policy": return category=self.translation.get_category(name) if not self.modifiers.has_key(category): self.modifiers[category]={} iter=self.store.append(None) self.modifiers[category]["iter"] = iter self.store.set_value(iter, 1, category) self.store.set_value(iter, 3, False)
self.modifiers[category][name]=val; iter=self.store.append(self.modifiers[category]["iter"]) self.store.set_value(iter, 0, val.isOn()) self.store.set_value(iter, 1, self.translation.get_value(name)) self.store.set_value(iter, 2, name) self.store.set_value(iter, 3, True)
def set(self,name,val): category=self.translation.get_category(name) self.modifiers[category][name].set(val) if self.isBoolean(name): self.booleanDirty=True else: self.tunableDirty=True
def isBoolean(self,name): c=self.translation.get_category(name) return isinstance(self.modifiers[c][name], Boolean)
def get_booleans(self): booleans={} for c in self.modifiers.keys(): for n in self.modifiers[c].keys(): if isinstance(self.modifiers[c][n], Boolean): booleans[n]=self.modifiers[c][n] return booleans def get_tunables(self): tunables={} for c in self.modifiers.keys(): for n in self.modifiers[c].keys(): if isinstance(self.modifiers[c][n], Tunable): tunables[n]=self.modifiers[c][n] return tunables
def save(self, boolconf): if self.booleanDirty == True: booleans=self.get_booleans() setseboolS="/usr/sbin/setsebool -P " for b in booleans.keys(): if booleans[b].save==1: setseboolS += "%s=%d " % (b, booleans[b].isOn()) boolconf[b]=str(booleans[b].isOn()) commands.getstatusoutput(setseboolS) # boolconf.write()
ctr=0 if self.tunableDirty == True: tunables=self.get_tunables() for b in tunables.keys(): if tunables[b].save==1: tunables[b].write() ctr=ctr+1 return ctr class TunableFile(Conf): def __init__(self,filename,rootdir=""): Conf.__init__(self, filename, commenttype='#') self.read() self.rewind() self.keys={} comment=[] self.rcs=1 while self.findnextline(): line=self.getline() if line=="": self.nextline() continue
line=line.strip() if line[0] == "#": comment.append(line) self.nextline() continue
val=line.split() if val[0] != "dnl" and val[0][:6] != "define": self.nextline() continue
key=val[0] if key == "dnl": key=val[1]
key=key.split("`")[1].split("'")[0]
self.keys[key]={}
if val[0] == "dnl": self.setValue(key,False) else: self.setValue(key,True)
self.keys[key]["comment"]=comment if len(comment)==0: self.setCommentstr(key,key) else: commentstr="" for c in comment: commentstr = "%s%s" % (commentstr,c[1:]) self.setCommentstr(key,commentstr) comment=[] self.nextline()
def setkey(self,key,type, value): self.keys[key][type]=value
def getKeys(self): return self.keys.keys()
def setValue(self,key,value): self.keys[key]["value"]=value
def getValue(self,key): return self.keys[key]["value"]
def setCommentstr(self,key,commentstr): self.keys[key]["commentstr"]=commentstr
def getCommentstr(self,key): return self.keys[key]["commentstr"]
def writetun(self): for key in self.keys: ret="" for l in self.keys[key]["comment"]: ret = "%s%s\n" % (ret, l) print "%s _(\"%s\") _(\"%s\")" % (key,self.filename,ret[2:].strip()) def out(self): ret="" for key in self.keys: for l in self.keys[key]["comment"]: ret = "%s%s\n" % (ret, l) if self.getValue(key)==False: ret="%sdnl define(`%s')\n\n" % (ret, key) else: ret="%sdefine(`%s')\n\n" % (ret, key) return ret def write(self): outfile=tempfile.mkstemp() os.write(outfile[0],self.out()) os.close(outfile[0]) os.system('/usr/bin/ci -u -m"control panel update" ' + self.filename+' </dev/null >/dev/null 2>&1') os.rename(outfile[1],self.filename) class selinuxPage: def __init__(self): self.selinuxsupport=True self.toplevel = gtk.VBox(False, 5) self.toplevel.set_border_width(5) self.pageLabel = gtk.Label(_("_SELinux")) self.pageLabel.set_use_underline(True) self.translation=Translation() self.tunableCtr=0 self.enabledToggle = gtk.CheckButton(_("Enabled (Modification Requires Reboot)")) self.enforcingToggle = gtk.CheckButton(_("Enforcing")) self.relabelToggle = gtk.CheckButton(_("Relabel on next reboot")) self.currentmodelabel = gtk.Label(_("Current:\t%s") % self.get_current_mode()) self.typelabel = gtk.Label(_("Policy Type:")) self.typelabel.set_use_underline(True) self.selinuxTypeOptionMenu = gtk.combo_box_new_text() self.typelabel.set_mnemonic_widget(self.selinuxTypeOptionMenu) self.tunableLabel = gtk.Label(_("Modify SELinux Policy")) self.tunableStore = gtk.TreeStore(gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT, gobject.TYPE_BOOLEAN) self.tunableView = gtk.TreeView() self.tunableView.set_headers_visible(False) self.tunableView.set_model(self.tunableStore) self.tunableStore.set_sort_column_id(1, gtk.SORT_ASCENDING)
checkbox = gtk.CellRendererToggle() checkbox.connect("toggled", self.tunable_toggled) col = gtk.TreeViewColumn('', checkbox, active = 0,visible=3) col.set_fixed_width(20) col.set_clickable(True) self.tunableView.append_column(col)
col = gtk.TreeViewColumn("", gtk.CellRendererText(), text=1) self.tunableView.append_column(col) self.tunableSW = gtk.ScrolledWindow() self.tunableSW.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.tunableSW.set_shadow_type(gtk.SHADOW_IN) self.tunableSW.add(self.tunableView)
if self.read_selinux_config() == None: self.toplevel.set_sensitive(False) self.selinuxsupport=False else: self.enabledToggle.connect("toggled", self.enabled_changed) self.enforcingToggle.connect("toggled", self.enforcing_changed) self.relabelToggle.connect("toggled", self.relabel_changed) self.refreshTunables(self.initialtype) # # This line must come after read_selinux_config # self.selinuxTypeOptionMenu.connect("changed", self.typemenu_changed) box = gtk.HBox(False, 5) box.pack_start(self.enabledToggle, False) self.toplevel.pack_start(box, False) self.toplevel.pack_start(gtk.HSeparator(), False)
box = gtk.HBox(False, 5) box.pack_start(self.enforcingToggle, False) box.pack_start(self.currentmodelabel, False) self.toplevel.pack_start(box, False) self.toplevel.pack_start(gtk.HSeparator(), False)
box = gtk.HBox(False, 5) box.pack_start(self.relabelToggle, False) self.toplevel.pack_start(box, False) self.toplevel.pack_start(gtk.HSeparator(), False)
box = gtk.HBox(False, 5) box.pack_start(self.typelabel, False) box.pack_start(self.selinuxTypeOptionMenu, True) self.toplevel.pack_start(box, False) self.toplevel.pack_start(gtk.HSeparator(), False)
self.toplevel.pack_start(self.tunableLabel, False) self.toplevel.pack_start(self.tunableSW, True)
self.dirty=False self.typechanged=False
def setup_relabel(self): fd=open(RELABELFILE,"w") fd.close() def reset_current_modelabel(self): self.currentmodelabel.set_text(_("Current:\t%s") % self.get_current_mode()) return None def get_current_mode(self): return commands.getoutput("/usr/sbin/getenforce") def set_current_mode(self,value): return commands.getoutput("/usr/sbin/setenforce %d" % value) def error_dialog (self, message, dialog_type=gtk.MESSAGE_WARNING): dialog = gtk.MessageDialog (None, gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL, dialog_type, gtk.BUTTONS_OK, message) dialog.set_position(gtk.WIN_POS_MOUSE) dialog.run () dialog.destroy () def verify(self, message): dlg = gtk.MessageDialog(None, 0, gtk.MESSAGE_INFO, gtk.BUTTONS_YES_NO, message) dlg.set_position(gtk.WIN_POS_MOUSE) dlg.show_all() rc = dlg.run() dlg.destroy() return rc
def info(self, message): dlg = gtk.MessageDialog(None, 0, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, message) dlg.set_position(gtk.WIN_POS_MOUSE) dlg.show_all() rc = dlg.run() dlg.destroy() return rc
def typemenu_changed(self, menu): self.dirty=True type=self.getType() if os.access(SELINUXDIR+type+"/src/policy/tunables", os.F_OK) == 0: #File doesn't exist. return self.doc = None return None if self.initialtype != type: if self.verify(_("Changing the policy type will cause a relabel of the entire file system on the next boot. Relabeling takes a long time depending on the size of the file system. Do you wish to continue?")) == gtk.RESPONSE_NO: menu.set_active(self.typeHistory) return None
self.relabelToggle.set_active(True) self.refreshTunables(type)
def loadBooleans(self): booleansList=commands.getoutput("/usr/sbin/getsebool -a").split("\n") for i in booleansList: rec=i.split() name=rec[0] on=rec[2]=="active" self.modifiers.add(name,Boolean(name,on)) def refreshTunables(self,type): self.modifiers=Modifiers(self.tunableStore) self.typeHistory=self.selinuxTypeOptionMenu.get_active() # Load Bools if type==self.initialtype: self.loadBooleans()
# Load Bools
fullpath=SELINUXDIR+type+"/src/policy/tunables/" if not os.path.isdir(fullpath): return for i in os.listdir(fullpath): if i[-4:] == ".tun" and os.path.isfile(fullpath+i): name=i.split(".")[0] if name=="distro": continue self.tunableCtr=self.tunableCtr+1 tunable=self.read_tunable_file(fullpath+i)
def relabel_changed(self, toggle): self.dirty=True def enabled_changed(self, toggle): self.dirty=True enabled=toggle.get_active() if self.initEnabled == False and enabled == True: if self.verify(_("Changing to SELinux enabled will cause a relabel of the entire file system on the next boot. Relabeling takes a long time depending on the size of the file system. Do you wish to continue?")) == gtk.RESPONSE_NO: toggle.set_active(False) return None self.relabelToggle.set_active(True)
self.enforcingToggle.set_sensitive(enabled) self.currentmodelabel.set_sensitive(enabled) self.tunableLabel.set_sensitive(enabled) self.tunableSW.set_sensitive(enabled) self.typelabel.set_sensitive(enabled) self.selinuxTypeOptionMenu.set_sensitive(enabled)
def enforcing_changed(self, toggle): self.dirty=True return
def get_label(self): return self.pageLabel
def get_page(self): return self.toplevel
def read_selinux_config(self): self.initialtype="targeted" self.boolconf={} self.types=[] if os.access(SELINUXDIR, os.F_OK) == 0: #File doesn't exist. return return None
self.conf=ConfShellVar(SELINUXDIR+"config") self.conf.rcs=1 if self.conf.has_key("SELINUX"): value=self.conf.vars["SELINUX"].upper() else: value="ENFORCING" self.conf.vars["SELINUX"]=value
self.initEnabled = ( value != "DISABLED" ) if value == "ENFORCING": self.enabledToggle.set_active(True) self.enforcingToggle.set_active(True) elif value == "PERMISSIVE": self.enabledToggle.set_active(True) self.enforcingToggle.set_active(False) elif value == "DISABLED": self.enabledToggle.set_active(False) self.enforcingToggle.set_active(False) self.enabled_changed(self.enabledToggle)
if os.access(RELABELFILE, os.F_OK) == 0: self.relabelToggle.set_active(False) else: self.relabelToggle.set_active(True) if self.conf.has_key("SELINUXTYPE"): self.initialtype=self.conf.vars["SELINUXTYPE"] else: self.conf.vars["SELINUXTYPE"]=self.initialtype n=0 current=n
for i in os.listdir(SELINUXDIR): if os.path.isdir(SELINUXDIR+i) and os.path.isdir(SELINUXDIR+i+"/policy"): self.types.append(i) self.selinuxTypeOptionMenu.append_text(i) if i == self.initialtype: current=n n=n+1 self.boolconf[i]=ConfShellVar(SELINUXDIR+self.initialtype+"/booleans") self.boolconf[i].rcs=1
self.selinuxTypeOptionMenu.set_active(current)
return 0
def read_tunable_file(self,file): try: tunable=TunableFile(file) for key in tunable.getKeys(): self.modifiers.add(key,Tunable(key,tunable.getValue(key), tunable,False)) except ValueError: return None return tunable
def checkbox_create(self, widget, row): print "Create" def tunable_toggled(self, widget, row): if len(row) == 1: return iter = self.tunableStore.get_iter(row) val = self.tunableStore.get_value(iter, 0) key = self.tunableStore.get_value(iter, 2) self.tunableStore.set_value(iter, 0 , not val) self.modifiers.set(key, not val)
def getType(self): return self.types[self.selinuxTypeOptionMenu.get_active()]
def getMode(self): choice = self.selinuxOptionMenu.get_active() if choice == ENFORCING: return "enforcing" elif choice == PERMISSIVE: return "permissive" elif choice == DISABLED: return "disabled" def apply(self): if self.selinuxsupport==False: return type=self.getType() if self.dirty == True: enabled=self.enabledToggle.get_active() enforcing=self.enforcingToggle.get_active() if enabled and enforcing: self.conf["SELINUX"]="Enforcing" else: if enabled: self.conf["SELINUX"]="Permissive" else: self.conf["SELINUX"]="Disabled" self.set_current_mode(enforcing) self.conf["SELINUXTYPE"]=type self.conf.write() if self.relabelToggle.get_active(): self.setup_relabel() else: if os.access(RELABELFILE, os.F_OK) != 0: os.unlink(RELABELFILE) if self.initialtype == type and self.modifiers.save(self.boolconf[type]): self.reloadPolicy() def reloadPolicy(self): dialog = gtk.MessageDialog (None, gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, _("Reloading Policy. This may take a minute.")) dialog.set_position(gtk.WIN_POS_MOUSE) dialog.show () dialog.get_toplevel().window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) while gtk.events_pending(): gtk.main_iteration()
command= "make -C %s/%s/src/policy reload" % (SELINUXDIR , self.getType() ) status=commands.getstatusoutput(command)[0] dialog.destroy () return status
|