#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# HnTool - A hardening tool for Linux/BSD
# Copyright (C) 2009 Authors
# Authors:
#   * Hugo Doria <mail at hugodoria dot org>
#   * Aurelio A. Heckert <aurium at gmail dot 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, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#

import sys

import string
from optparse import OptionParser
from optparse import OptionGroup

import HnTool.modules.util
import HnTool.modules
import HnTool.output

class HntoolCore:

    # HnTool's version
    # can't forget to change this
    HNTOOL_VERSION = 0.1

    def __init__(self):
        self.rule_modules = {}
        self.output_modules = {}
        self.report = []
        self.options = None

        self.opt_parser = OptionParser(
            usage="Usage: %prog [options]",
            version="%prog " + str(self.HNTOOL_VERSION))
        self.output_options = OptionGroup(self.opt_parser, "Output Options")
        self.rule_options = OptionGroup(self.opt_parser, "Rule Options")

    # Method to list all rules available
    def list_rules(self, *args):
        '''Method to list all output formats available'''

        print '-' * 31 + ' HnTool rule list ' + '-' * 31
        print
        for module in self.rule_modules:
            print string.ljust(self.rule_modules[module].short_name(), 16) +\
                ': ' + self.rule_modules[module].long_name()
        sys.exit(0)

    # Method to list all output formats available
    def list_output_formats(self, *args):
        '''Method to list all output formats available'''

        print '-' * 30 + ' HnTool output list ' + '-' * 30
        for module in output_modules:
            print string.ljust(module, 11) + ': ' \
            + output_modules[module].description
        sys.exit(0)

    # Loading all rule modules
    def load_modules(self):
        '''Method to load all rule modules'''

        for module in HnTool.modules.__all__:
            self.rule_modules[module] = \
               __import__('HnTool.modules.' + module, globals(), \
               locals(), [HnTool]).Rule(self.output_options)

    # Loading all output modules
    def load_output_modules(self):
        '''Method to load all output modules'''

        for module in HnTool.output.__formats__:
            self.output_modules[module] = \
               __import__('HnTool.output.' + module, globals(), \
               locals(), [HnTool]).Format(self.output_options)

    # Parsing all the configuration options
    def config_option_parser(self):
        '''Method to parse all the configuration options'''

        # -l/--list option: list all available rules
        self.opt_parser.add_option("-l", "--list",
                              action="callback",
                              callback=self.list_rules,
                              help="returns a list of available rules")

        # -t/--output_type: select the way that the report will
        # be generate (html or terminal, for now)
        self.opt_parser.add_option("-t", "--output_type",
                              action="store",
                              dest="output_format", default="terminal",
                              help="select the output format")

        # --list_output_type: list all available output formats
        self.opt_parser.add_option("--list_output_type",
                              action="callback",
                              callback=self.list_output_formats,
                              help="list the avaliable output formats")

        # adding the rules to they respective groups (rules or output)
        self.opt_parser.add_option_group(self.output_options)
        self.opt_parser.add_option_group(self.rule_options)

        self.options, args = self.opt_parser.parse_args(sys.argv[1:])

#TODO: define one error code for each error to allow automatic interactions.

    # Checking if all requirements are met
    def initial_check(self):
        '''Method to check if all HnTool's requirements are met'''

        # yes, only unix for now
        if not HnTool.modules.util.is_unix():
            print >> sys.stderr, \
            'Error: You must have a Unix(-like) box. (No candy for you)'
            sys.exit(2)

        # checking if we are root. we need to be. oh yeah, baby.
        if not HnTool.modules.util.is_root():
            print >> sys.stderr, 'Error: You must be root to run HnTool'
            print >> sys.stderr, ''
            print >> sys.stderr, self.opt_parser.print_help()
            sys.exit(2)

    # Main initialization
    def init_core(self):
        '''Method to run the initial checks and load all modules,
        output modules and configuration options'''

        # status message must not go to stdout to not mess with the output
        #format.
        self.initial_check() # checking HnTool's requirements
        self.load_modules() # loading all the modules
        self.load_output_modules() # loading all the output modules
        self.config_option_parser() # getting all the options
        print >> sys.stderr, '[ Starting HnTool checks... ]'

    # This is where we run all the tests
    def run_tests(self):
        '''Method to run all tests available on HnTool'''
        self.init_core() # main initialization

        # Run all the modules and its checks.
        # The results of each module goes to "report"
        for m in self.rule_modules:
            self.report.append({'title': self.rule_modules[m].long_name(), \
            'results': self.rule_modules[m].analyze(self.options)})

        # Give the report to the user
        self.output_modules[self.options.output_format].output(
            self.report,
            self.options
        )

hn = HntoolCore()
hn.run_tests()
