#!/usr/bin/python
#
# Copyright (C) 2007, 2008 Red Hat, Inc.
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# 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, see <http://www.gnu.org/licenses/>.
#

import os, sys

DATADIR = '/usr/share/system-config-firewall'
import sys
sys.path.append(DATADIR)

from fw_config import *
from fw_parser import parseArgs, parseSysconfigArgs, parseSELinuxArgs, \
     copyValues
from fw_iptables import *
from fw_sysconfig import *
from fw_sysctl import *
import fw_selinux
import fw_tui

# check euid
if os.geteuid() != 0:
    print _("\nERROR - You must be root to run lokkit.");
    sys.exit(1)

### parse command line arguments ###

config = parseArgs()

# no force mode in update
if config.update:
    config.force = False

old_config = None
# force mode: ignore old configuration
# else: use old configuration and command line arguments
if not config.force:
    ### load original configuration ###

    # initialize  old_config
    old_config = parseArgs([ ])

    # parse /etc/sysconfig/system-config-firewall or
    # /etc/sysconfig/system-config-securitylevel
    old_config = read_sysconfig_config(old_config)

    # parse selinux config
    selinux_args = fw_selinux.read() or [ ]
    old_config = parseSELinuxArgs(selinux_args, options=old_config)

    config = parseArgs(options=copyValues(old_config))

if config.update:
    # update firewall if not disabled
    if not config.enabled:
        sys.exit(0)
    config.quiet = True
    config.nostart = False

### ui ###

if not config.quiet:
    if len(sys.argv[1:]) == 0:
        ui = fw_tui.ui()
        if not ui.run(config):
            sys.exit(0)

### write configuration ###

# load ip*tables-config only if there is something to do
if (config.add_module and len(config.add_module) > 0) or \
       (config.remove_module and len(config.remove_module) > 0):
    # load IPv4 configuration
    ip4tables_conf = ip4tablesConfig(IP4TABLES_CFG)
    ip4tables_conf.read()
    # load IPv6 configuration
    ip6tables_conf = ip6tablesConfig(IP6TABLES_CFG)
    ip6tables_conf.read()

    _modules = [ ]
    try:
        _modules.append(ip4tables_conf.get("IPTABLES_MODULES"))
    except:
        pass
    try:
        _modules.append(ip6tables_conf.get("IP6TABLES_MODULES"))
    except:
        pass

    # setup modules
    for modules in _modules:
        if config.add_module:
            for module in config.add_module:
                modalias = None
                if module[:3] == "nf_":
                    modalias = "ip_"+module[3:]
                if module[:3] == "ip_":
                    modalias = "nf_"+module[3:]
                if module not in modules and modalias not in modules:
                    modules.append(module)
        if config.remove_module:
            for module in config.remove_module:
                modalias = None
                if module[:3] == "nf_":
                    modalias = "ip_"+module[3:]
                if module[:3] == "ip_":
                    modalias = "nf_"+module[3:]
                if module in modules:
                    modules.remove(module)
                if modalias in modules:
                    modules.remove(modalias)

    # write IPv4 configuration
    ip4tables_conf.write()
    # write IPv6 configuration
    ip6tables_conf.write()

ip4tables = iptablesClass(IP4TABLES_RULES)
ip6tables = ip6tablesClass(IP6TABLES_RULES)
ip4t_status = ip6t_status = 0

if config.enabled:
    # write new config
    ip4tables.write(config)    
    ip6tables.write(config)

    if not config.nostart:
        # start ip*tables
        ip4t_status = ip4tables.restart(config.verbose)
        if ip4t_status == 150:
            # ipv4 disabled, ignore
            ip4t_status = 0
        if ip4t_status != 0:
            print _("Failed to restart %s.") % "iptables"
        ip6t_status = ip6tables.restart(config.verbose)
        if ip6t_status == 150:
            # ipv6 disabled, ignore
            ip6t_status = 0
        if ip6t_status != 0:
            print _("Failed to restart %s.") % "ip6tables"
else:
    if not config.nostart:
        # stop ip*tables
        ip4t_status = ip4tables.stop(config.verbose)
        if ip4t_status != 0:
            print _("Failed to stop %s.") % "iptables"
        ip6t_status = ip6tables.stop(config.verbose)
        if ip6t_status != 0:
            print _("Failed to stop %s.") % "ip6tables"
    # remove config
    try:
        ip4tables.unlink()
    except Exception, msg:
        ip4t_status += 1
        print _("Failed to remove %s.") % ip4tables.filename
        if config.verbose:
            print msg
    try:
        ip6tables.unlink()
    except Exception, msg:
        ip6t_status += 1
        print _("Failed to remove %s.") % ip6tables.filename
        if config.verbose:
            print msg

# write /etc/sysconfig/system-config-securitylevel and
# /etc/sysconfig/system-config-firewall
c_status = int(write_sysconfig_config(CONFIG, config) == False)
if c_status != 0:
    print _("Failed to write %s.") % CONFIG

# sysctl
if config.masq and len(config.masq) > 0:
    sysctl = sysctlClass(SYSCTL_CONFIG)
    sysctl.read()
    if sysctl.get("net.ipv4.ip_forward") != "1":
        sysctl.set("net.ipv4.ip_forward", "1")
        sysctl.write()
        sysctl.reload()

# selinux
se_status = 0
if config.selinux or config.selinuxtype:
    if old_config:
        if not config.selinux:
            config.selinux = old_config.selinux
        if not config.selinuxtype:
            config.selinuxtype = old_config.selinuxtype
    if not config.selinux:
        config.selinux = DEFAULT_SELINUX_MODE
    if not config.selinuxtype:
        config.selinuxtype = DEFAULT_SELINUX_TYPE

    if config.selinux != old_config.selinux or \
           config.selinuxtype != old_config.selinuxtype:
        se_status = int(fw_selinux.write(config) == False)
        if se_status != 0:
            print _("Failed to write selinux configuration.")
        else:
            fw_selinux.setenforce(config.selinuxtype)

sys.exit(ip4t_status + ip6t_status + c_status + se_status)
