## modules/pc/protocol_config.c

/* [<][>][^][v][top][bottom][index][help] */

## FUNCTIONS

This source file includes following functions.

1. find_command
2. show_commands
3. command_help
4. command_quit
5. show_const
6. show_consts
7. show_props
8. show_thread
9. show_whois
10. show_access
11. command_execute
12. command_show
13. command_repeat
14. set_const
15. set_consts
16. set_props
17. command_set
18. command_sql
19. process_input
20. log_config
21. echo_off
22. echo_on
23. authenticate_user
24. PC_interact

    /***************************************
      $Revision: 1.8 $

      Protocol config module (pc).  This is the protocol that the admin uses to
      talk to the server.

      Status: NOT REVUED, NOT TESTED

      ******************/ /******************
      Filename            : protocol_config.c
      Author              : ottrey@ripe.net
      OSs Tested          : Solaris
      To Do               : Add a facility to take callbacks instead of
                            hard-coding menu options.
      ******************/ /******************
      Copyright (c) 1999                              RIPE NCC

      All Rights Reserved

      Permission to use, copy, modify, and distribute this software and its
      documentation for any purpose and without fee is hereby granted,
      provided that the above copyright notice appear in all copies and that
      both that copyright notice and this permission notice appear in
      supporting documentation, and that the name of the author not be
      used in advertising or publicity pertaining to distribution of the
      software without specific, written prior permission.

      THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
      ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
      AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
      DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
      AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      ***************************************/
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <time.h>       /* Time stuff */
    #include <sys/ioctl.h>      /* Terminal control stuff */
    #include <termio.h>      /* Terminal control stuff */

    #include "mysql_driver.h"
    #include "constants.h"
    #include "properties.h"
    #include "thread.h"
    #include "protocol_config.h"
    #include "access_control.h"

    /*+ Each command has a +*/
    typedef struct _command {
      const char *name;                          /*+ Name to be invoked. +*/
      char *(*function)(char *);      /*+ Function to be invoked. +*/
      const char *help;                                /*+ Command help. +*/
    } Command;

    /*
     * Forward declarations
     */
    static char *command_help(char *input);
    static char *command_quit(char *input);
    static char *command_show(char *input);
    static char *command_repeat(char *input);
    static char *show_const(char *input);
    static char *show_consts(char *input);
    static char *show_props(char *input);
    static char *show_thread(char *input);
    static char *show_whois(char *input);
    static char *show_access(char *input);
    static char *command_set(char *input);
    static char *set_const(char *input);
    static char *set_consts(char *input);
    static char *set_props(char *input);
    static char *command_sql(char *input);

    /*+
     * Contains the command definitions
    +*/
    static struct _command command[] = {
      {"help"   , command_help   , HELP_HELP   },
      {"quit"   , command_quit   , HELP_QUIT   },
      {"show"   , command_show   , HELP_SHOW   },
      {"repeat" , command_repeat , HELP_REPEAT },
      {"set"    , command_set    , HELP_SET    },
      {"sql"    , command_sql    , HELP_SQL    },
      NULL
    };

    /*+
     * Contains the show commands
    +*/
    static struct _command show[] = {
      {"const"   , show_const   , HELP_SHOW_CONST   },
      {"consts"  , show_consts  , HELP_SHOW_CONSTS  },
      {"props"   , show_props   , HELP_SHOW_PROPS   },
      {"thread"  , show_thread  , HELP_SHOW_THREAD  },
      {"whois"   , show_whois   , HELP_SHOW_WHOIS   },
      {"access"  , show_access  , HELP_SHOW_ACCESS  },
      NULL
    };

    /*+
     * Contains the set commands
    +*/
    static struct _command set[] = {
      {"const"  , set_const  , HELP_SET_CONST  },
      {"consts" , set_consts , HELP_SET_CONSTS },
      {"props"  , set_props  , HELP_SET_PROPS  },
      NULL
    };

    static int find_command(char *comm_name, Command *comm) {
    /* [<][>][^][v][top][bottom][index][help] */
      int i, index;
      char comm_buffer[STR_L];

      if (comm_name != NULL) {
        strcpy(comm_buffer, comm_name);
        strtok(comm_buffer, " \t");
        for (i=0, index=-1; comm[i].name != NULL; i++) {
          if ( strcmp(comm_buffer, comm[i].name) == 0) {
            index = i;
            break;
          }
        }
      }
      else {
        index = -2;
      }

      return index;
    } /* find_command() */

    static char *show_commands(Command *comm) {
    /* [<][>][^][v][top][bottom][index][help] */
      char *str;
      char help_buffer[STR_XL];
      char help_comm[STR_M];
      int i;

      sprintf(help_buffer, " commands are:\n\n");
      i = 0;
      while (comm[i].name != NULL) {
        sprintf(help_comm, "%s\t%s\n", comm[i].name, comm[i].help);
        strcat(help_buffer, help_comm);
        i++;
      }

      str = (char *)calloc(1, strlen(help_buffer)+1);
      strcpy(str, help_buffer);

      return str;
    } /* show_commands() */

    /*
     * Command functions
     */
    static char *command_help(char *input) {
    /* [<][>][^][v][top][bottom][index][help] */
      char *str;
      char *str1;
      char output_buffer[STR_XXL];
      char *command_name;
      int index;

      strcpy(output_buffer, "");

      strtok(input, " \t");
      command_name = (char *)strtok(NULL, " \t");

      index = find_command(command_name, command);

      switch (index) {
        case -2:
          strcat(output_buffer, "Main");
          str1 = show_commands(command);
          strcat(output_buffer, str1);
          free(str1);
          break;

        case -1:
          strcat(output_buffer, HELP_ERROR);
          strcat(output_buffer, command_name);
          break;

        default:
          strcat(output_buffer, command[index].help);
      }

      /*
      str = (char *)CopyString(output_buffer);
      */
      str = (char *)calloc(1, strlen(output_buffer)+1);
      strcpy(str, output_buffer);

      return str;
    } /* command_help() */

    static char *command_quit(char *input) {
    /* [<][>][^][v][top][bottom][index][help] */
        /* Client wishes to quit. */
      return NULL;
    } /* command_quit() */

    static char *show_const(char *input) {
    /* [<][>][^][v][top][bottom][index][help] */
      /* Client wishes to show constants. */
      char *result;
      char *name;
      char *tmp_input;

      tmp_input = (char *)calloc(1, strlen(input)+1);
      strcpy(tmp_input, input);

      /* The name will be the third token in stuff */
      strtok(tmp_input, " ");
      strtok(NULL, " ");
      name = (char *)strtok(NULL, " ");

      result = CO_const_to_string(name);

      free(tmp_input);
      return result;

    } /* show_const() */

    static char *show_consts(char *input) {
    /* [<][>][^][v][top][bottom][index][help] */
      /* Client wishes to show constants. */
      return CO_to_string();

    } /* show_consts() */

    static char *show_props(char *input) {
    /* [<][>][^][v][top][bottom][index][help] */
      /* Client wishes to show properties. */
      return PR_to_string();

    } /* show_props() */

    static char *show_thread(char *input) {
    /* [<][>][^][v][top][bottom][index][help] */
      /* Client wishes to show thread information. */
      return TH_to_string();

    } /* show_thread() */

    static char *show_whois(char *input) {
    /* [<][>][^][v][top][bottom][index][help] */
      /* Client wishes to show whois query information. */
      return "WQ_to_string();";

    } /* show_whois() */

    static char *show_access(char *input) {
    /* [<][>][^][v][top][bottom][index][help] */
      /* Client wishes to show whois query information. */
      return AC_to_string();

    } /* show_access() */

    static char *command_execute(char *input, char *comm_name, Command *comm) {
    /* [<][>][^][v][top][bottom][index][help] */
      char *str;
      char *str1;
      char output_buffer[STR_XXL];
      char tmp[STR_L];
      char *name;
      int index;
      char *tmp_input;

      /* Make a copy of the input */
      tmp_input = (char *)calloc(1, strlen(input)+1);
      strcpy(tmp_input, input);

      strtok(tmp_input, " \t");
      name = (char *)strtok(NULL, " \t");

      index = find_command(name, comm);

      switch (index) {
        case -2:
          str1 = show_commands(comm);
          sprintf(output_buffer, "%s%s", comm_name, str1);
          free(str1);
          break;

        case -1:
          sprintf(output_buffer, "%s invalid command: %s", comm_name, name);
          break;

        default:
          sprintf(output_buffer, "%s", comm[index].function(input));
      }

      /*
      str = (char *)CopyString(output_buffer);
      */
      str = (char *)calloc(1, strlen(output_buffer)+1);
      strcpy(str, output_buffer);

      free(tmp_input);

      return str;
    } /* command_execute() */

    static char *command_show(char *input) {
    /* [<][>][^][v][top][bottom][index][help] */
      return command_execute(input, "Show", show);
    } /* command_show() */

    static char *command_repeat(char *input) {
    /* [<][>][^][v][top][bottom][index][help] */
      char *command_ptr;

      /* Goto the bit after "repeat n " */
      for (command_ptr=input+7; command_ptr[0] != ' ' || (command_ptr[0] >= '0' && command_ptr[0] <= '9'); command_ptr++);

      return command_ptr+1;

    } /* command_show() */

    static char *set_const(char *input) {
    /* [<][>][^][v][top][bottom][index][help] */
      /* Client wishes to set a constant. */
      char *result;
      char result_buf[STR_M];
      char *tmp_input;
      char *name;
      char *value;
      int value_len;
      char *stuff;
      char *str;

      tmp_input = (char *)calloc(1, strlen(input)+1);
      strcpy(tmp_input, input);

      stuff = (char *)strtok(tmp_input, "=");

      /* The value will be after the '=' */
      value = (char *)strtok(NULL, "=");

      /* The name will be the third token in stuff */
      strtok(stuff, " ");
      strtok(NULL, " ");
      name = (char *)strtok(NULL, " ");

      /* Remove any quotes */
      if (value[0] == '"') {
        value++;
      }
      value_len=strlen(value);
      if (value[value_len-1] == '"') {
        value[value_len-1]='\0';
      }

      printf("set_const name=(%s), value=(%s)\n", name, value);
      if (CO_set_const(name, value) == 0) {
        strcpy(result_buf, "Constant successfully set\n");
      }
      else {
        str = CO_const_to_string(name);
        sprintf(result_buf, "Constant not successfully set\nReverting to:   %s=%s\n", name, str);
        free(str);
      }

      result = (char *)calloc(1, strlen(result_buf)+1);
      strcpy(result, result_buf);

      free(tmp_input);
      return result;
    } /* set_const() */

    static char *set_consts(char *input) {
    /* [<][>][^][v][top][bottom][index][help] */
      /* Client wishes to set constants. */
      return CO_set();
    } /* set_consts() */

    static char *set_props(char *input) {
    /* [<][>][^][v][top][bottom][index][help] */
      /* Client wishes to set properties. */
      return PR_set();
    } /* set_props() */

    static char *command_set(char *input) {
    /* [<][>][^][v][top][bottom][index][help] */
      return command_execute(input, "Set", set);
    } /* command_set() */

    static char *command_sql(char *input) {
    /* [<][>][^][v][top][bottom][index][help] */
      char *str;
      char output_buffer[STR_XXL];
      char *current_character;
      char *whois_query;
      char *sql_str;

      char *res=NULL;

      SQ_result_set_t *sql_result=NULL;
      SQ_connection_t *sql_connection;

      sql_connection = SQ_get_connection(CO_get_host(), CO_get_database_port(), CO_get_database(), CO_get_user(), CO_get_password() );

      if (sql_connection == NULL) {
        printf("/* Check for errors */\n");
      }

      /* skip over the "sql" */
      sql_str = input+3;
      /* skip over white space */
      while (sql_str[0] == ' ') {
        sql_str++;
      }

      strcpy(output_buffer, "");

      if (sql_connection != NULL) {
        if (strcmp(sql_str, "status") == 0) {
          /* Get the status of the database */
          res = SQ_info_to_string(sql_connection);
        }
        else {
          if (strcmp(sql_str, "") == 0) {
            /* Execute the default query (from the properties file) */
            sql_result = SQ_execute_query(sql_connection, CO_get_query());
          }
          else {
            /* Execute an sql query */
            sql_result = SQ_execute_query(sql_connection, sql_str);
          }
          if (sql_result != NULL) {
            res = SQ_result_to_string(sql_result);
          }
          else {
            printf("no results\n");
          }
        }
        if (res != NULL) {
          sprintf(output_buffer, "%s", res);
        }
        else {
          printf("empty results\n");
        }
      }
      else {
        printf("Failed to make connection\n");
      }

      /*
      strcat(output_buffer, mysql_info(sql_connection));
      */

      strcat(output_buffer, "XXX Results from mysql_info(sql_connection) is meant to go here.  But it's not working!");

      /*
      str = (char *)CopyString(output_buffer);
      */
      str = (char *)calloc(1, strlen(output_buffer)+1);
      strcpy(str, output_buffer);

      free(res);
      SQ_free_result(sql_result);

      SQ_close_connection(sql_connection);

      return str;

    } /* command_sql() */

    /* process_input() */
    /*++++++++++++++++++++++++++++++++++++++

      Process the input.

      int sock  The socket to connect to.

      More:
      +html+ <PRE>
      Author:
            ottrey
      +html+ </PRE>
      ++++++++++++++++++++++++++++++++++++++*/
    static int process_input(char *input, int sock) {
    /* [<][>][^][v][top][bottom][index][help] */
      int connected = 1;
      char *input_ptr;
      char *output;
      char *command_name;
      int  index;
      int repeat=0;

      input_ptr = input;

      if (strncmp(input, "repeat", 6) == 0) {
        /* XXX This is a really dodgy call, that hopefully converts
        the string to the value of the first found integer. */
        repeat = atoi(input+7);
        input_ptr= command_repeat(input);
      }

      index = find_command(input_ptr, command);

      do {
        switch (index) {
          case -1:
            /* Command not found */
            output = command_help(NULL);
            break;

          default:
            output = command[index].function(input_ptr);
        }

        if(output == NULL) {
          connected = 0;
        } else {
          /*
          printf("thread output=\n%s\n", output);
          */
          if ( CO_get_clear_screen() == 1 ) {
            SK_puts(sock, CLEAR_SCREEN);
          }
          SK_puts(sock, output);
          SK_puts(sock, "\n");
          SK_puts(sock, CO_get_prompt());
        }

        free(output);

        if (repeat > 0) {
          repeat--;
          sleep(CO_get_sleep_time());
        }

      } while (repeat > 0);

      return connected;

    } /* process_input() */

    static void log_config(const char *user, const char *status) {
    /* [<][>][^][v][top][bottom][index][help] */
      FILE *logf;
      char *str;
      time_t now;

      time(&now);

      if (CO_get_config_logging() == 1) {

        if (strcmp(CO_get_config_logfile(), "stdout") == 0) {
          printf(LOG_CONFIG, TH_get_id(), user, status, ctime(&now));
        }
        else {
          logf = fopen(CO_get_config_logfile(), "a");
          fprintf(logf, LOG_CONFIG, TH_get_id(), user, status, ctime(&now));
          fclose(logf);
        }
      }

    } /* log_config() */

    /* XXX Doh! These only change the server's terminal.  We need some
       tricky escape sequence to send over the socket. */
    static void echo_off(int sock) {
    /* [<][>][^][v][top][bottom][index][help] */
      struct termio state;

      ioctl(0, TIOCGETP, &state);
      state.c_lflag &= ~ECHO;
      ioctl(0, TIOCSETP, &state);
    } /* echo_off() */

    /* XXX Doh! These only change the server's terminal.  We need some
       tricky escape sequence to send over the socket. */
    static void echo_on(int sock) {
    /* [<][>][^][v][top][bottom][index][help] */
      struct termio state;

      ioctl(0, TIOCGETP, &state);
      state.c_lflag |= ECHO;
      ioctl(0, TIOCSETP, &state);
    } /* echo_on() */

    static char *authenticate_user(int sock) {
    /* [<][>][^][v][top][bottom][index][help] */
      char *user = NULL;
      char Salt[2] = "DB";
      char input[MAX_INPUT_SIZE];
      int read_result;
      char *password=NULL;
      char *user_password=NULL;
      char user_buf[10];

      SK_puts(sock, LOGIN_PROMPT);
      read_result = SK_gets(sock, input, MAX_INPUT_SIZE);

      strncpy(user_buf, input, 10);

      SK_puts(sock, PASSWD_PROMPT);
      /* XXX These aren't working.
      SK_puts(sock, ECHO_ON);
      echo_off(sock);
      */
      read_result = SK_gets(sock, input, MAX_INPUT_SIZE);
      /* XXX These aren't working.
      echo_on(sock);
      SK_puts(sock, ECHO_OFF);
      */

      password = (char *)crypt(input, Salt);

      user_password = PR_get_property(user_buf, DEFAULT_USER_NAME);

      if (user_password != NULL) {
        if (strcmp(password, user_password) == 0) {
          user = (char *)calloc(1, strlen(user_buf)+1);
          strcpy(user, user_buf);
        }
      }

      if (user == NULL) {
        log_config(user_buf, "unsuccesful login attempt");
      }

      return user;

    } /* authenticate_user() */

    void PC_interact(int sock) {
    /* [<][>][^][v][top][bottom][index][help] */
      char input[MAX_INPUT_SIZE];
      int connected = 1;
      int read_result;
      char *welcome;
      char *user=NULL;

      /* Welcome the client */
      SK_puts(sock, CO_get_welcome());

      /* Authenticate the user */
      if (CO_get_authenticate() == 1) {
        user = authenticate_user(sock);
      }
      else {
        user="nobody";
      }

      if (user != NULL) {
        /* Log admin logging on */
        log_config(user, "logged on");

        SK_puts(sock, CO_get_prompt());

        while (connected) {
          /* Read input */
          read_result = SK_gets(sock, input, MAX_INPUT_SIZE);
          if (read_result == -1) {
            connected = 0;
          }
          else if (read_result == -2) {
            printf("Thread received a control-c\n");
            connected = 0;
          }
          connected = process_input(input, sock);
        }

        /* Log admin logging off */
        log_config(user, "logged off");
      }

      /* Close the socket */
      SK_close(sock);

    } /* PC_interact() */

/* [<][>][^][v][top][bottom][index][help] */