#
# selinuxPage.py - GUI for SELinux page in system-config-securitylevel
#
# Brent Fox <bfox@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
sys.path.append('/usr/share/system-config-securitylevel')

##
## I18N
## 
from rhpl.translate import _, N_
import rhpl.translate as translate
translate.textdomain ("system-config-securitylevel")

class selinuxPage:
    def __init__(self):
        self.toplevel = gtk.VBox(gtk.FALSE, 5)
        self.toplevel.set_border_width(5)        
        self.pageLabel = gtk.Label(_("_SELinux"))
        self.pageLabel.set_use_underline(gtk.TRUE)

        label = gtk.Label(_("Security _Enhanced Linux (SELinux):"))
        label.set_use_underline(gtk.TRUE)
        
        self.selinuxOptionMenu = gtk.OptionMenu()
        label.set_mnemonic_widget(self.selinuxOptionMenu)
        self.selinuxMenu = gtk.Menu()
        
        for i in (_("Active"), _("Warn"), _("Disabled")):
            self.selinuxMenu.add(gtk.MenuItem(i))
        self.selinuxOptionMenu.set_menu(self.selinuxMenu)
        self.selinuxOptionMenu.connect("changed", self.menu_changed)

        self.tunableLabel = gtk.Label(_("SELinux Tunables:"))
        self.tunableStore = gtk.ListStore(gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
        self.tunableView = gtk.TreeView()
        self.tunableView.set_headers_visible(gtk.FALSE)
        self.tunableView.set_model(self.tunableStore)

        self.checkbox = gtk.CellRendererToggle()
        self.checkbox.connect("toggled", self.tunable_toggled)
        col = gtk.TreeViewColumn('', self.checkbox, active = 0)
        col.set_fixed_width(20)
        col.set_clickable(gtk.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_NEVER, gtk.POLICY_AUTOMATIC)
        self.tunableSW.set_shadow_type(gtk.SHADOW_IN)
        self.tunableSW.add(self.tunableView)

        box = gtk.HBox(gtk.FALSE, 5)
        box.pack_start(label, gtk.FALSE)
        box.pack_start(self.selinuxOptionMenu, gtk.TRUE)
        self.toplevel.pack_start(box, gtk.FALSE)
        self.toplevel.pack_start(gtk.HSeparator(), gtk.FALSE)

## Re-enable when SELinux is in better shape
##         self.toplevel.pack_start(self.tunableLabel, gtk.FALSE)
##         self.toplevel.pack_start(self.tunableSW, gtk.TRUE)

##         if self.read_selinux_file() == None:
##             self.toplevel.set_sensitive(gtk.FALSE)

##         if self.read_tunable_file() == None:
##             self.tunableSW.set_sensitive(gtk.FALSE)

    def menu_changed(self, menu):
        if menu.get_history() == 2:
            self.tunableLabel.set_sensitive(gtk.FALSE)
            self.tunableSW.set_sensitive(gtk.FALSE)            
        else:
            self.tunableLabel.set_sensitive(gtk.TRUE)
            self.tunableSW.set_sensitive(gtk.TRUE)            

    def get_label(self):
        return self.pageLabel

    def get_page(self):
        return self.toplevel

    def read_selinux_file(self):
        if os.access("/etc/sysconfig/selinux", os.F_OK) == 0:
            #File doesn't exist.  return
            return None

        lines = open("/etc/sysconfig/selinux").readlines()
        for line in lines:
            if line[:8] == "SELINUX=":
                key, value = string.split(line, "=")
                value = string.strip(value)
                if value == "enforcing":
                    self.selinuxOptionMenu.set_history(0)
                elif value == "permissive":
                    self.selinuxOptionMenu.set_history(1)
                elif value == "disabled":
                    self.selinuxOptionMenu.set_history(2)

        return 0

    def read_tunable_file(self):
        if os.access("/etc/security/selinux/src/policy/tunable.xml", os.F_OK) == 0:
            #File doesn't exist.  return
            self.doc = None
            return None
        
        self.doc = libxml2.parseFile ("/etc/security/selinux/src/policy/tunable.xml")
        root = self.doc.getRootElement()
        node = root.children

        while node is not None:
            if node.type != "element":
                node = node.next
                continue

            if node.name == "group":
                iter = self.tunableStore.append()

                cnode = node.children
                while cnode is not None:
                    
                    if cnode.name == "description":
                        self.tunableStore.set_value(iter, 1, cnode.content)

                    if cnode.name == "prefix":
                        self.tunableStore.set_value(iter, 2, cnode)
                        if cnode.content == "":
                            self.tunableStore.set_value(iter, 0, gtk.TRUE)
                        elif cnode.content == "#":
                            self.tunableStore.set_value(iter, 0, gtk.FALSE)

                    cnode = cnode.next

            node = node.next

        return 0

    def write_tunable_file(self):
        self.doc.saveFile("/etc/security/selinux/src/policy/tunable.xml")

    def extract_xml_to_text(self):
        root = self.doc.getRootElement()
        node = root.children

        fd = open("/etc/security/selinux/src/policy/tunable.te", "w")

        while node is not None:
            if node.type != "element":
                node = node.next
                continue
            if node.name == "group":

                cnode = node.children
                while cnode is not None:

                    if cnode.name == "description":
                        fd.write("#%s\n" % cnode.content)

                    if cnode.name == "prefix":
                        fd.write(cnode.content)

                    if cnode.name == "id":
                        fd.write("%s\n\n" % cnode.content)

                    cnode = cnode.next

            node = node.next

        fd.close()

    def tunable_toggled(self, widget, row):
        iter = self.tunableStore.get_iter((int(row),))
        val = self.tunableStore.get_value(iter, 0)
        self.tunableStore.set_value(iter, 0 , not val)
        

    def apply(self):
        choice = self.selinuxOptionMenu.get_history()

        if choice == 0 or choice == 1:

## Re-enable when SELinux is in better shape
##             #Don't query the table if there's SELinux is disabled
##             iter = self.tunableStore.get_iter_first()
##             while iter:
##                 if self.tunableStore.get_value(iter, 0) == gtk.TRUE:
##                     node = self.tunableStore.get_value(iter,2)

##                     node.setContent("")
##                 elif self.tunableStore.get_value(iter, 0) == gtk.FALSE:
##                     node = self.tunableStore.get_value(iter,2)
##                     node.setContent("#")
##                 iter = self.tunableStore.iter_next(iter)

##             if self.doc:
##                 self.write_tunable_file()
##                 self.extract_xml_to_text()
##                 self.doc.freeDoc()
                
            if choice == 0:
                return "--selinux=enforcing"
            elif choice == 1:
                return "--selinux=permissive"

        elif choice == 2:
            return "--selinux=disabled"

