/* fwprofiles.c  --  eurephiadm fwprofiles command:
 *                   Manages firewall profiles
 *
 *  GPLv2 only - Copyright (C) 2009 - 2012
 *               David Sommerseth <dazo@users.sourceforge.net>
 *
 *  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; version 2
 *  of the License.
 *
 *  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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

/**
 * @file   fwprofiles.c
 * @author David Sommerseth <dazo@users.sourceforge.net>
 * @date   2009-03-29
 *
 * @brief  eurephia fwprofiles command, to manage firewall profiles.
 *
 */

#include <stdio.h>
#include <string.h>
#include <assert.h>

#ifdef HAVE_LIBXML2
#include <libxml/tree.h>
#endif

#define MODULE "eurephia::fwProfiles" /**< Needed to define the active module before including argparser.h */
#include <eurephia_nullsafe.h>
#include <eurephia_context.h>
#include <eurephia_log.h>
#include <eurephia_xml.h>
#include <eurephia_values_struct.h>
#include <eurephiadb_session_struct.h>
#include <eurephiadb_mapping.h>
#include <eurephiadb_driver.h>
#include <eurephia_values.h>

#include "../argparser.h"
#include "../xsltparser.h"


/**
 * Help screens for the fwprofiles command
 *
 * @param page which help screen to display
 */
void display_fwprofiles_help(int page)
{
        switch( page ) {
        case 'l':
                printf("The fwprofiles list mode will show all registered firewall profiles.\n"
                       "\n"
                       "     -v | --verbose               Show more details\n"
                       "\n"
                       "Filters:\n"
                       "     -a | --accessprofile <id>    Numeric ID.\n"
                       "     -f | --fw-destination <name> Reference used by the firewall\n"
                       "     -i | --uid <user id>         Numeric user ID\n"
                       "     -n | --username <username>   User name\n"
                       "     -c | --certid <certid>       Numeric reference to a certificate\n"
                       "     -e | --email <email addr>    e-mail address in certificates\n"
                       "     -d | --digest <SHA1 digest>  Certificate SHA1 digest\n\n");
                break;

        case 'A':
                printf("The fwprofiles add mode will register a new firewall profile.\n"
                       "\n"
                       "     -d | --description    <text> Description of the firewall destination/rule\n"
                       "     -f | --fw-destination <name> The reference used by the firewall module\n"
                       "\n"
                       );
                break;

        case 'D':
                printf("The fwprofiles delete mode will delete a firewall profile.\n"
                       "\n"
                       "     -a | --accessprofile  <id>   Description of the firewall destination/rule\n"
                       "     -f | --fw-destination <name> The reference used by the firewall module\n"
                       "\n"
                       );
                break;

        default:
                printf("Available modes for the fwprofiles command are:\n\n"
                       "     -A | --add          Add a new firewall profile\n"
                       "     -D | --delete       Delete a firewall profile\n"
                       "     -l | --list         List available firewall profiles\n"
                       "     -h | --help <mode>  Show help\n\n");
                break;
        }
}


/**
 * Help screen wrapper.  Used by cmd_Help()
 */
void help_fwProfiles()
{
        display_fwprofiles_help(0);
}


/**
 * Help screen wrapper for the fwprofile help function.
 *
 * @param ctx   eurephiaCTX
 * @param sess  eurephiaSESSION of the current logged in user
 * @param cfg   eurephiaVALUES struct of the current configuration
 * @param argc  argument count for the eurephiadm command
 * @param argv  argument table for the eurephiadm command
 *
 * @return returns 0 on success, otherwise 1.
 */
int help_fwProfiles2(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv)
{
        e_options fwprofilesargs[] = {
                {"--list", "-l", 0},
                {"--add", "-A", 0},
                {"--delete", "-D", 0},
                {NULL, NULL, 0}
        };
        int i = 1;
        display_fwprofiles_help(eurephia_getopt(&i, argc, argv, fwprofilesargs));
        return 0;
}


/**
 * fwprofiles list mode.  Lists all registered firewall profiles.
 *
 * @param ctx   eurephiaCTX
 * @param sess  eurephiaSESSION of the current logged in user
 * @param cfg   eurephiaVALUES struct of the current configuration
 * @param argc  argument count for the eurephiadm command
 * @param argv  argument table for the eurephiadm command
 *
 * @return returns 0 on success, otherwise 1.
 */
int list_profiles(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv)
{
        xmlDoc *profiles_xml = NULL, *srch_xml = NULL;
        xmlNode *fmap_n = NULL, *srch_n = NULL;
        char *xsltparams[] = {"view", "'list'", NULL};
        int i = 0;

        e_options fwprofilesargs[] = {
                {"--verbose", "-v", 0},
                {"--help", "-h", 0},
                {"--accessprofile", "-a", 1},
                {"--fw-destination", "-f", 1},
                {"--uid", "-i", 1},
                {"--username", "-u", 1},
                {"--certid", "-c", 1},
                {"--email", "-e", 1},
                {"--digest", "-d", 1},
                {NULL, NULL, 0}
        };

        eurephiaXML_CreateDoc(ctx, 1, "firewall_profiles", &srch_xml, &srch_n);
        xmlNewProp(srch_n, (xmlChar *) "mode", (xmlChar *) "search");

        fmap_n = xmlNewChild(srch_n, NULL, (xmlChar *) "fieldMapping", NULL);
        xmlNewProp(fmap_n, (xmlChar *) "table", (xmlChar *) "firewall_profiles");

        for( i = 1; i < argc; i++ ) {
                switch( eurephia_getopt(&i, argc, argv, fwprofilesargs) ) {
                case 'v':
                        xsltparams[1] = "'details'";
                        break;

                case 'a':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "accessprofile", (xmlChar *) optargs[0]);
                        break;

                case 'f':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "fwprofile", (xmlChar *) optargs[0]);
                        break;

                case 'i':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "uid", (xmlChar *) optargs[0]);
                        break;

                case 'u':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "username", (xmlChar *) optargs[0]);
                        break;

                case 'c':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "certid", (xmlChar *) optargs[0]);
                        break;

                case 'e':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "email", (xmlChar *) optargs[0]);
                        break;

                case 'd':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "digest", (xmlChar *) optargs[0]);
                        break;

                case 'h':
                        display_fwprofiles_help('l');
                        xmlFreeDoc(srch_xml);
                        return 0;

                default:
                        xmlFreeDoc(srch_xml);
                        return 1;
                }
        }

        profiles_xml = eDBadminFirewallProfiles(ctx, srch_xml);
        xmlFreeDoc(srch_xml);
        if( profiles_xml == NULL ) {
                fprintf(stderr, "%s: Error retrieving firewall profiles\n", MODULE);
                return 1;
        }

        xslt_print_xmldoc(stdout, cfg, profiles_xml, "fwadmin.xsl", (const char **) xsltparams);

        xmlFreeDoc(profiles_xml);
        return 0;
}


/**
 * fwprofile add/delete mode.  Registers or removes firewall profiles.
 *
 * @param ctx   eurephiaCTX
 * @param sess  eurephiaSESSION of the current logged in user
 * @param cfg   eurephiaVALUES struct of the current configuration
 * @param argc  argument count for the eurephiadm command
 * @param argv  argument table for the eurephiadm command
 *
 * @return returns 0 on success, otherwise 1.
 */
int addelete_profile(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv)
{
        xmlDoc *result_xml = NULL, *srch_xml = NULL;
        xmlNode *fmap_n = NULL, *srch_n = NULL;
        eurephiaRESULT *res = NULL;
        int i = 0, rc = 1, mode = 0;

        e_options addargs[] = {
                        {"--help", "-h", 0},
                        {"--description", "-d", 1},
                        {"--fw-destination", "-f", 1},
                        {NULL, NULL, 0}
        };

        e_options deleteargs[] = {
                        {"--help", "-h", 0},
                        {"--accessprofile", "-a", 1},
                        {"--fw-destination", "-f", 1},
                        {NULL, NULL, 0}
        };


        e_options *fwprofilesargs = NULL;

        eurephiaXML_CreateDoc(ctx, 1, "firewall_profiles", &srch_xml, &srch_n);
        if( (strcmp(argv[0], "--add") == 0) || (strcmp(argv[0], "-A") == 0) ) {
                xmlNewProp(srch_n, (xmlChar *) "mode", (xmlChar *) "add");
                fwprofilesargs = addargs;
                mode = 'A';
        } else if( (strcmp(argv[0], "--delete") == 0) || (strcmp(argv[0], "-D") == 0) ) {
                xmlNewProp(srch_n, (xmlChar *) "mode", (xmlChar *) "delete");
                fwprofilesargs = deleteargs;
                mode = 'D';
        } else {
                fprintf(stderr, "%s: Invalid mode\n", MODULE);
                xmlFreeDoc(srch_xml);
                return 1;
        }

        fmap_n = xmlNewChild(srch_n, NULL, (xmlChar *) "fieldMapping", NULL);
        xmlNewProp(fmap_n, (xmlChar *) "table", (xmlChar *) "firewall_profiles");

        for( i = 1; i < argc; i++ ) {
                switch( eurephia_getopt(&i, argc, argv, fwprofilesargs) ) {
                case 'a':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "accessprofile", (xmlChar *) optargs[0]);
                        break;

                case 'd':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "description", (xmlChar *) optargs[0]);
                        break;

                case 'f':
                        xmlNewChild(fmap_n, NULL, (xmlChar *) "fwprofile", (xmlChar *) optargs[0]);
                        break;

                case 'h':
                        display_fwprofiles_help(mode);
                        return 0;

                default:
                        return 1;
                }
        }

        result_xml = eDBadminFirewallProfiles(ctx, srch_xml);
        xmlFreeDoc(srch_xml);
        if( result_xml == NULL ) {
                fprintf(stderr, "%s: Error registering firewall profiles\n", MODULE);
                return 1;
        }

        res = eurephiaXML_ParseResultMsg(ctx, result_xml);
        if( res == NULL ) {
                fprintf(stderr, "%s: Error registering firewall profiles. No results returned\n", MODULE);
                return 1;

        } else {
                if( res->resultType == exmlERROR ) {
                        fprintf(stderr, "%s: %s\n", MODULE, res->message);
                        rc = 1;
                } else {
                        fprintf(stdout, "%s: %s\n", MODULE, res->message);
                        rc = 0;
                }
        }
        free_nullsafe(ctx, res);
        xmlFreeDoc(result_xml);

        return rc;
}


/**
 * Main function for the fwprofiles command
 *
 * @param ctx   eurephiaCTX
 * @param sess  eurephiaSESSION of the current logged in user
 * @param cfg   eurephiaVALUES struct of the current configuration
 * @param argc  argument count for the eurephiadm command
 * @param argv  argument table for the eurephiadm command
 *
 * @return returns 0 on success, otherwise 1.
 */
int cmd_fwProfiles(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv)
{
        char **mode_argv;
        int rc = 0, i = 0, mode_argc = 0;
        e_options fwprofilesargs[] = {
                {"--list", "-l", 0},
                {"--add", "-A", 0},
                {"--delete", "-D", 0},
                {"--help", "-h", 0},
                {NULL, NULL, 0}
        };
        int (*mode_fnc) (eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv);

        assert((ctx != NULL) && (ctx->dbc != NULL));

        mode_fnc = NULL;
        for( i = 1; i < argc; i++ ) {
                switch( eurephia_getopt(&i, argc, argv, fwprofilesargs) ) {
                case 'l':
                        mode_fnc = list_profiles;
                        break;

                case 'A':
                case 'D':
                        mode_fnc = addelete_profile;
                        break;

                case 'h':
                        mode_fnc = help_fwProfiles2;

                default:
                        break;
                }
                if( mode_fnc != NULL ) {
                        break;
                }
        }

        // If we do not have any known mode defined, exit with error
        if( mode_fnc == NULL )  {
                fprintf(stderr, "%s: Unknown argument.  No mode given\n", MODULE);
                return 1;
        }

        // Allocate memory for our arguments being sent to the mode function
        mode_argv = (char **) calloc(sizeof(char *), (argc - i)+2);
        assert(mode_argv != NULL);

        // Copy over only the arguments needed for the mode
        mode_argc = eurephia_arraycp(i, argc, argv, mode_argv, (argc - i));

        // Call the mode function
        rc = mode_fnc(ctx, sess, cfg, mode_argc, mode_argv);
        free_nullsafe(ctx, mode_argv);

        return rc;

}
