#
# securitylevel.py - GUI front end code for basic system security
#
# Brent Fox <bfox@redhat.com>
#
# Copyright 2002, 2003, 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 gobject
import sys
import os
sys.path.append('/usr/share/system-config-securitylevel')
import checklist
import selinuxPage

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

##
## Icon for windows
##

iconPixbuf = None      
try:
    iconPixbuf = gtk.gdk.pixbuf_new_from_file("/usr/share/system-config-securitylevel/pixmaps/system-config-securitylevel.png")
except:
    pass

class childWindow:
    #You must specify a runPriority for the order in which you wish your module to run
    runPriority = 50
    moduleName = _("Security Level")
    moduleClass = "reconfig"
    nameTag = _("Security Level Configuration")
    commentTag = _("Configure system security level")

    def destroy(self, args):
        gtk.mainquit()
    
    def __init__(self):
        self.selinuxPage = None
        self.doDebug = None
        self.toplevel = gtk.VBox(gtk.FALSE, 5)
        self.mainVBox = gtk.VBox(gtk.FALSE, 5)        
        self.iconBox = gtk.HBox()
        self.title = gtk.Label(_("Security Level Configuration"))
        self.title.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse ("white"))

        self.label = gtk.Label(_("Please choose the security level for the system."))
        self.label.set_line_wrap(gtk.TRUE)
        self.label.set_alignment(0.0, 0.5)
        self.securityLabel = gtk.Label(_("Security level:"))

        self.securityOptionMenu = gtk.OptionMenu()
        self.securityMenu = gtk.Menu()
        self.enableString = (_("Enable firewall"))
        self.noneString = (_("Disable firewall"))
        self.enableItem = gtk.MenuItem(self.enableString)
        self.enableItem.connect("activate", self.firewall_activated)
        self.noneItem = gtk.MenuItem(self.noneString)
        self.noneItem.connect("activate", self.none_activated)
        self.securityMenu.append(self.enableItem)
        self.securityMenu.append(self.noneItem)        
        self.securityOptionMenu.set_menu(self.securityMenu)
        
        self.securityBox = gtk.HBox(gtk.FALSE, 5)
        self.securityBox.pack_start(self.securityLabel, gtk.FALSE)

        self.trustedLabel = gtk.Label(_("Trusted devices:"))
        self.trustedLabel.set_alignment(0.0, 0.5)
        self.trustedList = checklist.CheckList(1)
        self.trustedSW = gtk.ScrolledWindow()
        self.trustedSW.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        self.trustedSW.set_shadow_type(gtk.SHADOW_IN)
        self.trustedSW.add(self.trustedList)        

        self.incomingLabel = gtk.Label(_("Trusted services:"))
        self.incomingList = checklist.CheckList(1)
        self.incomingSW = gtk.ScrolledWindow()
        self.incomingSW.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
        self.incomingSW.set_shadow_type(gtk.SHADOW_IN)
        self.incomingSW.add(self.incomingList)        
        self.incomingLabel.set_alignment(0.0, 0.5)
        self.otherLabel = gtk.Label(_("Other ports: (1029:tcp)"))
        self.otherLabel.set_alignment(0.0, 0.5)
        self.otherEntry = gtk.Entry()
        self.table = gtk.Table(3, 2)
        self.table.set_row_spacings(3)
        self.table.set_col_spacings(5)
        self.table.set_sensitive(gtk.FALSE)

        #Add icon to the top frame
        p = None
        try:
            p = gtk.gdk.pixbuf_new_from_file("../pixmaps/system-config-securitylevel.png")
        except:
            try:
                p = gtk.gdk.pixbuf_new_from_file("/usr/share/system-config-securitylevel/pixmaps/system-config-securitylevel.png")
            except:
                pass

        if p:
            self.icon = gtk.Image()
            self.icon.set_from_pixbuf(p)

        self.devices = self.networkDevices()
        for device in self.devices:
            self.trustedList.append_row((device, ""), gtk.FALSE)

        self.serviceDict = {"SSH":"ssh", "Telnet":"telnet", "WWW (HTTP)":"http",
                     _("Mail (SMTP)"):"smtp", "FTP":"ftp"}
        for item in self.serviceDict.keys():
            self.incomingList.append_row((item, ""), gtk.FALSE)

    def firewall_activated(self, *args):
        self.table.set_sensitive(gtk.TRUE)

    def none_activated(self, *args):
        self.table.set_sensitive(gtk.FALSE)        

    def networkDevices(self):
        netdevices = []
        lines = open("/proc/net/dev", "r").readlines()
        # skip first two lines, they are header
        lines = lines[2:]
        for line in lines:
            dev = string.strip(line[0:6])
            if dev != "lo":
                netdevices.append (dev)

        return netdevices  

    def enableTable(self, *args):
        self.table.set_sensitive(gtk.TRUE)

    def okClicked(self, *args):
        rc = self.apply()
        if rc == 0:
            self.destroy(args)

    def apply(self, *args):
        args = ['--quiet']

        level = self.securityOptionMenu.get_children()[0].get_text()
        
        if level == self.noneString:
            args.append('--disabled')
        elif level == self.enableString:
            args.append('--enabled')

        count = 0
        for device in self.devices:
            val = self.trustedList.get_active(count)
            if val == 1:
                args.append('--trust=' + device)
            count = count + 1

        count = 0            
        for service in self.serviceDict.keys():
            val = self.incomingList.get_active(count)
            if val == 1:
                args.append('--port=' + self.serviceDict[service] + ':tcp')
            count = count + 1

        portstring = string.strip(self.otherEntry.get_text())
        portlist = ""
        bad_token_found = 0
        bad_token = ""
        if portstring != "":
            tokens = string.split(portstring, ',')
            for token in tokens:
                try:
                    #- if there's a colon in the token, it's valid
                    if string.index(token,':'):
                        token = string.strip(token)
                        parts = string.split(token, ':')
                        if len(parts) > 2: # more than one colon
                            bad_token_found = 1
                            bad_token = token
                        else:
                            # udp and tcp are the only valid protos
                            if parts[1] == 'tcp' or parts[1] == 'udp':
                                args.append('--port=' + parts[0] + ":" + parts[1])
                            else: # found protocol !tcp && !udp
                                bad_token_found = 1
                                bad_token = token
                                pass
                except:
                    bad_token_found = 1
                    bad_token = token
                    pass
                                                                                
            if bad_token_found == 1: # raise a warning
                text = _("Invalid port given: %s.  The proper format is "
                         "'port:protocol, port:protocol'.  For example, "
                         "'1234:udp, 3456:tcp'") % (bad_token,)
                                                                                
                dlg = gtk.MessageDialog(None, 0, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, text)
                dlg.set_modal(gtk.TRUE)
                dlg.set_icon(iconPixbuf)
                dlg.set_position(gtk.WIN_POS_CENTER)
                dlg.show_all()
                dlg.run()
                dlg.destroy()
                self.otherEntry.grab_focus()
                return 1

        if self.doDebug:
            print "don't call lokkit if in debug mode"
            return 0

        dlg = gtk.MessageDialog(None, 0, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO,
                                _("Clicking the 'Yes' button will set the security level of the "
                                "system and override any "
                                "existing firewall configuration.  Are you sure that you want "
                                "to do this?"))
        dlg.set_position(gtk.WIN_POS_CENTER)
        dlg.set_modal(gtk.TRUE)
        dlg.set_icon(iconPixbuf)
        dlg.show_all()
        result = dlg.run()

        if result == gtk.RESPONSE_NO:
            dlg.destroy()
            return 1

        fd = open('/etc/sysconfig/system-config-securitylevel', 'w')
        fd.write("#Configuration file for system-config-securitylevel\n")
        fd.write("#Copyright (c) 2002 Red Hat, Inc.  all rights reserved\n\n")

        for arg in args[1:]:
            fd.write(arg + "\n")
        fd.close()

        if self.selinuxPage:
            args.append(self.selinuxPage.apply())

        path = '/usr/sbin/lokkit'

        lokkit = os.fork()
        if (not lokkit):
            args.insert(0, path)
            os.execv(path, args)                

        return 0

    def readFile(self):
        path = "/etc/sysconfig/system-config-securitylevel"
        if os.access(path, os.R_OK) == 1:
            lines = open(path, 'r').readlines()
        else:
            #The file isn't there, so just return and keep on going
            self.enableTable()
            return

        devicesList = []
        servicesList = []
        portsList = []

        self.enableTable()
        for line in lines:
            if string.strip(line) != "" and string.strip(line)[0] != "#":
                if string.strip(line) == "--high":
                    self.securityOptionMenu.set_history(0)
                elif string.strip(line) == "--medium":
                    self.securityOptionMenu.set_history(0)
                elif string.strip(line) == "--enabled":
                    self.securityOptionMenu.set_history(0)
                if string.strip(line) == "--disabled":
                    self.securityOptionMenu.set_history(1)
                    self.none_activated()
                    return
                if line[:8] == "--trust=":
                    key, device = string.split(line, "=")
                    devicesList.append(string.strip(device))
                if line[:7] == "--port=":
                    key, value = string.split(line, "=")
                    service, protocol = string.split(value, ":")
                    service = string.strip(service)
		    if service == '22' or service == 'ssh':
			service = 'ssh'
                    elif service == '80' or service == 'http':
			service = 'http'
		    elif service == '23' or service == 'telnet':
			service = 'telnet'
		    elif service == '21' or service == 'ftp':
			service = 'ftp'
		    elif service == '25' or service == 'smtp':
		    	service = 'smtp'
                    else:
                        portsList.append(string.strip(value))
                        continue
                    servicesList.append(service)

        iter = self.trustedList.store.get_iter_first()
        while iter:
            if self.trustedList.store.get_value(iter, 1) in devicesList:
                self.trustedList.store.set_value(iter, 0, gtk.TRUE)
            iter = self.trustedList.store.iter_next(iter)

        iter = self.incomingList.store.get_iter_first()
        while iter:
            if self.serviceDict[self.incomingList.store.get_value(iter, 1)] in servicesList:
                self.incomingList.store.set_value(iter, 0, gtk.TRUE)
            iter = self.incomingList.store.iter_next(iter)

        self.otherEntry.set_text(string.join(portsList, ", "))

    def launch(self, doDebug = None):
        self.doDebug = doDebug
        self.securityOptionMenu.set_size_request(200, -1)
        self.securityBox.pack_start(self.securityOptionMenu, gtk.FALSE)

        self.table.attach(self.incomingLabel, 0, 1, 0, 1, gtk.FILL)
        self.table.attach(self.incomingSW, 1, 2, 0, 1, gtk.FILL, gtk.SHRINK)
        self.table.attach(self.trustedLabel, 0, 1, 1, 2, gtk.FILL)
        self.table.attach(self.trustedSW, 1, 2, 1, 2, gtk.FILL, gtk.SHRINK)
#        self.table.attach(self.otherLabel, 0, 1, 2, 3, gtk.FILL)
#        self.table.attach(self.otherEntry, 1, 2, 2, 3, gtk.FILL)
        self.mainVBox.set_border_width(10)
        self.mainVBox.set_spacing(5)

        self.mainVBox.pack_start(self.label, gtk.FALSE)
        self.mainVBox.pack_start(self.securityBox, gtk.FALSE)
        self.mainVBox.pack_start(gtk.HSeparator(), gtk.FALSE)
        self.mainVBox.pack_start(self.table, gtk.FALSE)

        self.readFile()

        return self.mainVBox, self.icon, self.moduleName

    def stand_alone(self):
        self.securityOptionMenu.set_size_request(240, -1)
        self.securityBox.pack_start(self.securityOptionMenu, gtk.TRUE)

        self.mainWindow = gtk.Window()
        self.mainWindow.set_title(_("Security Level Configuration"))
        self.mainWindow.connect("destroy", self.destroy)
        self.mainWindow.set_icon(iconPixbuf)
        self.mainWindow.set_position(gtk.WIN_POS_CENTER)
        self.mainWindow.set_border_width(10)

        self.notebook = gtk.Notebook()
        #XXX - Remove when SELinux is in better shape
        self.notebook.set_show_tabs(gtk.FALSE)
        self.notebook.set_show_border(gtk.FALSE)        
        #XXX - Cut to here

        bb = gtk.HButtonBox()
        bb.set_layout(gtk.BUTTONBOX_END)
        bb.set_border_width(5)
        bb.set_spacing(10)
        okButton = gtk.Button(stock='gtk-ok')
        okButton.connect("clicked", self.okClicked)
        cancelButton = gtk.Button(stock='gtk-cancel')
        cancelButton.connect("clicked", self.destroy)
        self.table.attach(self.incomingLabel, 0, 1, 0, 1, gtk.FILL)
        self.table.attach(self.incomingSW, 1, 2, 0, 1, gtk.EXPAND|gtk.FILL, gtk.SHRINK)
        self.table.attach(self.trustedLabel, 0, 1, 1, 2, gtk.FILL)
        self.table.attach(self.trustedSW, 1, 2, 1, 2, gtk.FILL, gtk.SHRINK)
        self.table.attach(self.otherLabel, 0, 1, 2, 3, gtk.FILL)
        self.table.attach(self.otherEntry, 1, 2, 2, 3, gtk.FILL)

        bb.pack_start(cancelButton)
        bb.pack_start(okButton)

        #Packing
        self.iconBox.pack_start(self.icon, gtk.FALSE)
        self.iconBox.pack_start(self.label, gtk.FALSE)
        self.iconBox.set_spacing(5)
        firewallLabel = gtk.Label(_("_Firewall Options"))
        firewallLabel.set_use_underline(gtk.TRUE)
        self.mainVBox.pack_start(self.securityBox, gtk.FALSE)
        self.mainVBox.pack_start(gtk.HSeparator(), gtk.FALSE)
        self.mainVBox.pack_start(self.table, gtk.FALSE)
        self.mainVBox.pack_start(gtk.HSeparator(), gtk.FALSE)

        self.mainVBox.set_border_width(5)
        self.mainVBox.set_spacing(5)
        self.toplevel.pack_start(self.iconBox, gtk.FALSE)
        self.toplevel.pack_start(self.notebook)
        self.toplevel.pack_start(bb, gtk.FALSE)
        self.mainWindow.add(self.toplevel)

        self.readFile()

        self.notebook.append_page(self.mainVBox, firewallLabel)

#        self.selinuxPage = selinuxPage.selinuxPage()
#        self.notebook.append_page(self.selinuxPage.get_page(), self.selinuxPage.get_label())
        self.mainWindow.show_all()
        gtk.mainloop()
