Source File modules/pc/protocol_config.c

    1    | /***************************************
    2    |   $Revision: 1.37 $
    3    |
    4    |   Protocol config module (pc).  This is the protocol that the admin uses to
    5    |   talk to the server.
    6    |
    7    |   Status: NOT REVUED, NOT TESTED
    8    |
    9    |   ******************/ /******************
    10   |   Filename            : protocol_config.c
    11   |   Authors             : ottrey@ripe.net - initial design
    12   |                         marek@ripe.net - restructured and rewritten
    13   |
    14   |   To Do               : Add a facility to take callbacks instead of
    15   |                         hard-coding menu options.
    16   |                         Add in all the menu support provided by the GLib
    17   |                         libraries.
    18   |                         (Remove strtok if multiple threads are to be used.)
    19   | 			use gnu readline with expansion and history
    20   |   ******************/ /******************
    21   |   Copyright (c) 1999                              RIPE NCC
    22   |
    23   |   All Rights Reserved
    24   |
    25   |   Permission to use, copy, modify, and distribute this software and its
    26   |   documentation for any purpose and without fee is hereby granted,
    27   |   provided that the above copyright notice appear in all copies and that
    28   |   both that copyright notice and this permission notice appear in
    29   |   supporting documentation, and that the name of the author not be
    30   |   used in advertising or publicity pertaining to distribution of the
    31   |   software without specific, written prior permission.
    32   |
    33   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    34   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
    35   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
    36   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
    37   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    38   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    39   |   ***************************************/
    40   | #include <stdio.h>
    41   | #include <stdlib.h>
    42   | /*** solaris' header file doesn't contain the crypt definition...
    43   |      #include <unistd.h> */
    44   |
    45   | extern char* crypt(const char *, const char *);   /* crypt stuff */
    46   | #include <time.h>       /* Time stuff */
    47   | #include <sys/ioctl.h>  /* Terminal control stuff */
    48   |
    49   | #include "thread.h"
    50   | #include "constants.h"
    51   | #include "properties.h"
    52   | #include <glib.h>
    53   |
    54   | #include "sk.h"
    55   | #include "ta.h"
    56   |
    57   | #include "ut_string.h"
    58   | #include "memwrap.h"
    59   |
    60   | #include "pc_commands.h"
    61   |
    62   | #define PC_IMPL
    63   | #include "protocol_config.h"
    64   |
    65   |
    66   | /*++++++++++++++++++++++++++++++++++++++
    67   |
    68   |   Finds a command by name in the array of command function structures.
    69   |
    70   |   int find_command     returns the index to the correct row of the array, or -1
    71   |                        if the command could not be found.
    72   |
    73   |   char *comm_name      name of the command
    74   |
    75   |   Command *comm        array of command function structures.
    76   |   ++++++++++++++++++++++++++++++++++++++*/
    77   | static
    78   | int find_command(char *comm_name, Command *comm)
    79   | {
    80   |   int i;
    81   |   char *comm_buffer = wr_string(comm_name);
    82   |   char *token, *cursor;
    83   |   int index = -1;
    84   |
    85   |   cursor = comm_buffer;
    86   |   if( (token = strsep(&cursor, " \t")) != NULL) {
    87   |     for (i=0; comm[i].name != NULL; i++) {
    88   |       if ( strcmp(token, comm[i].name) == 0) {
    89   | 	index = i;
    90   | 	break;
    91   |       }
    92   |     }
    93   |   }
    94   |
    95   |   wr_free(comm_buffer);
    96   |
    97   |   return index; /* returns -1 when command not found */
    98   | } /* find_command() */
    99   |
    100  |
    101  | int show_commands(Command *comm, char *comm_name, GString *output)
    102  | {
    103  |   int i = 0;
    104  |
    105  |   g_string_sprintfa(output, "%scommands are:\n\n", comm_name);
    106  |   while (comm[i].name != NULL) {
    107  |     g_string_sprintfa(output, "%s\t%s\n", comm[i].name, comm[i].help);
    108  |     i++;
    109  |   }
    110  |
    111  |   return 1;
    112  | } /* show_commands() */
    113  |
    114  |
    115  | /*++++++++++++++++++++++++++++++++++++++
    116  |
    117  |   int command_execute
    118  |                       executes a command from the given array, matching
    119  | 		      given name. Passes input, output and condat to the
    120  | 		      function found in the array. Command name is
    121  | 		      removed from the input line so only next words are
    122  | 		      passed over to the function.
    123  |
    124  | 		      returns the code of the last command. Code
    125  | 		      PC_RET_QUIT is reserved to indicate that the connection
    126  | 		      should be closed.
    127  |
    128  |   Command *comm       array of command function structures (defined in
    129  |                       protocol_config.h)
    130  |
    131  |   char *comm_name     name of the command to be run
    132  |
    133  |   char *input         rest of the command line
    134  |
    135  |   GString *output     dynamically built output string
    136  |
    137  |   sk_conn_st *condat  socket structure for this connection (some commands
    138  |                       use it directly instead of storing the output)
    139  |
    140  |   ++++++++++++++++++++++++++++++++++++++*/
    141  | int command_execute(Command *comm, char *comm_name,
    142  | 		    char *input, GString *output, sk_conn_st *condat)
    143  | {
    144  |   char *name, *next_word, *tmp_input;
    145  |   int index, result=0;
    146  |
    147  |   /* find the command in the string - first whitespace delimited word */
    148  |   /* make a copy of the input */
    149  |   dieif( (tmp_input = wr_string(input)) == NULL );
    150  |   next_word = tmp_input;
    151  |
    152  |   /* find the first word and set the pointer to the rest of the string */
    153  |   name = strsep(&next_word, " \t");
    154  |
    155  |   if( name != NULL && strlen(name) != 0 ) {
    156  |     index = find_command(name, comm);
    157  |     if( index != -1 ) {
    158  |       if( next_word != NULL ) {
    159  | 	/* advance the input pointer to the next word */
    160  | 	while(  *next_word != '\0'
    161  | 		&& isspace( *(unsigned char *)next_word) ) {
    162  | 	  next_word++;
    163  | 	}
    164  |       }
    165  |       else {
    166  | 	next_word = "";
    167  |       }
    168  |
    169  |       /* run, Forrest, run...*/
    170  |       result = comm[index].function(next_word, output, condat);
    171  |     }
    172  |     else {
    173  |       g_string_sprintfa(output, "invalid %scommand: %s\n", comm_name, name);
    174  |       show_commands(comm, comm_name, output);
    175  |       result = 2;
    176  |     }
    177  |   }
    178  |   else {
    179  |     show_commands(comm, comm_name, output);
    180  |     result = 2;
    181  |   }
    182  |
    183  |   free(tmp_input);
    184  |
    185  |   return result;
    186  | } /* command_execute() */
    187  |
    188  |
    189  |
    190  |
    191  |
    192  |
    193  |
    194  | /* proces_input() */
    195  | /*++++++++++++++++++++++++++++++++++++++
    196  |
    197  |   Process the input. Finds the proper command in the top level command
    198  |   array and invokes the function associated with it with the input and
    199  |   output data as arguments.
    200  |
    201  |   int process_input          returns 1 if the connection is to be kept
    202  |                              or 0 when it should be finished - that is,
    203  | 			     when command_execute() returns PC_RET_QUIT.
    204  |
    205  |   char *input                input (presumably a command)
    206  |
    207  |   sk_conn_st *condat         connection data
    208  |
    209  |   More:
    210  |   +html+ <PRE>
    211  |   Author:
    212  |         ottrey
    213  | 	marek - changes and documentation.
    214  |   +html+ </PRE>
    215  |   ++++++++++++++++++++++++++++++++++++++*/
    216  | static
    217  | int process_input(char *input, sk_conn_st *condat)
    218  | {
    219  |   int  index;
    220  |   int res=0;
    221  |   GString *output = g_string_new("");
    222  |
    223  |   index = find_command(input, command);
    224  |
    225  |   switch (index) {
    226  |   case -1:
    227  |     /* Command not found */
    228  |     command_help(NULL, output, condat);
    229  |     break;
    230  |
    231  |   default:
    232  |     res = command_execute(command, "", input, output, condat);
    233  |   }
    234  |
    235  |   if(res != PC_RET_QUIT) {
    236  |     /*
    237  |       printf("thread output=\n%s\n", output);
    238  |     */
    239  |     if ( CO_get_clear_screen() == 1 ) {
    240  |       SK_cd_puts(condat, CLEAR_SCREEN);
    241  |     }
    242  |     SK_cd_puts(condat,  output->str);
    243  |     SK_cd_printf(condat, "\n\n=%d= %s", res, CO_get_prompt());
    244  |
    245  |   }
    246  |
    247  |   g_string_free( output, TRUE );
    248  |
    249  |   /* the return value is the connection state: 1=still open, 0=to be closed
    250  |    */
    251  |
    252  |   return (res != PC_RET_QUIT);
    253  | } /* process_input() */
    254  |
    255  |
    256  | /*++++++++++++++++++++++++++++++++++++++
    257  |
    258  |   Authenticates the user - asks for password and checks it. The password is
    259  |   echoed by the tcp stack, to disable that one would have to attach a tty
    260  |   to this connection and switch to raw mode or try the hard way - renegotiate
    261  |   the telnet connection to switch to character mode (and, possibly, back).
    262  |   The latter has the drawback that to do it right it has to be able to check
    263  |   whether there's telnet on the other side - otherwise, if the connection
    264  |   is made by a program just connecting to the socket, garbage will result.
    265  |   However, in such case password checking might be not a good idea.
    266  |
    267  |   sk_conn_st *condat
    268  |
    269  |   More:
    270  |   +html+ <PRE>
    271  |   Author:
    272  |         ottrey
    273  | 	marek - slight changes and documentation.
    274  |   +html+ </PRE>
    275  |   ++++++++++++++++++++++++++++++++++++++*/
    276  | static
    277  | char *authenticate_user(sk_conn_st *condat)
    278  | {
    279  |   char *user = NULL;
    280  |   const char Salt[2] = "DB";
    281  |   char input[MAX_INPUT_SIZE];
    282  |   int read_result;
    283  |   char *password=NULL;
    284  |   char *user_password=NULL;
    285  |   char user_buf[10];
    286  |
    287  |   SK_cd_puts(condat, LOGIN_PROMPT);
    288  |   read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE);
    289  |
    290  |   strncpy(user_buf, input, 10);
    291  |
    292  |   SK_cd_puts(condat, PASSWD_PROMPT);
    293  |   /* XXX These aren't working.
    294  |   SK_puts(sock, ECHO_ON);
    295  |   echo_off(sock);
    296  |   */
    297  |   read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE);
    298  |   /* XXX These aren't working.
    299  |   echo_on(sock);
    300  |   SK_puts(sock, ECHO_OFF);
    301  |   */
    302  |
    303  |   password = crypt(input, Salt);
    304  |
    305  |   user_password = PR_get_property(user_buf, DEFAULT_USER_NAME);
    306  |
    307  |   if (user_password != NULL) {
    308  |     if (strcmp(password, user_password) == 0) {
    309  |       /*user = (char *)calloc(1, strlen(user_buf)+1);*/
    310  |       dieif( wr_malloc((void **)&user, strlen(user_buf)+1) != UT_OK);
    311  |       strcpy(user, user_buf);
    312  |     }
    313  |   }
    314  |
    315  |
    316  |   return user;
    317  |
    318  | } /* authenticate_user() */
    319  |
    320  |
    321  |
    322  | /*++++++++++++++++++++++++++++++++++++++
    323  |
    324  |   Main function that talks to the user connected on the given socket.
    325  |   Starts by authenticating the user (if this mode is active)
    326  |   and greeting her with the uptime data. Then it loops reading and executing
    327  |   commands until the "quit" command (or any other command that causes
    328  |   process_input to return 0).
    329  |
    330  |   int sock        connected client socket
    331  |
    332  |   ++++++++++++++++++++++++++++++++++++++*/
    333  | void PC_interact(int sock) {
    334  |   char input[MAX_INPUT_SIZE];
    335  |   int connected = 1;
    336  |   char *user=NULL;
    337  |   sk_conn_st condat;
    338  |
    339  |   memset( &condat, 0, sizeof(condat));
    340  |   condat.sock = sock;
    341  |   SK_getpeerip(sock, &(condat.rIP));
    342  |   condat.ip = SK_getpeername(sock); /* XXX *alloc involved */
    343  |
    344  |   /* Welcome the client */
    345  |   SK_cd_puts(&condat, CO_get_welcome());
    346  |
    347  |   /* Authenticate the user */
    348  |   if (CO_get_authenticate() == 1) {
    349  |     user = authenticate_user(&condat);
    350  |
    351  |     if (user == NULL) {
    352  |       ER_inf_va(FAC_PC, ASP_PC_I_SESSION,
    353  | 		"unsuccesful login attempt from %s", condat.ip );
    354  |     }
    355  |   }
    356  |   else {
    357  |     user="nobody";
    358  |   }
    359  |
    360  |   if (user != NULL) {
    361  |
    362  |     /* Log admin logging on */
    363  |     ER_inf_va(FAC_PC, ASP_PC_I_SESSION,
    364  | 		"user %s from %s logged on", user, condat.ip );
    365  |
    366  |     {
    367  |       show_uptime("", NULL, &condat);
    368  |     }
    369  |
    370  |     SK_cd_printf(&condat, "=0= %s", CO_get_prompt());
    371  |
    372  |     while (condat.rtc==0 && connected) {
    373  |       char *icopy;
    374  |
    375  |       /* Read input. Quit if no input (socket closed) */
    376  |       if( SK_cd_gets(&condat, input, MAX_INPUT_SIZE) <= 0 ) {
    377  | 	break;
    378  |       }
    379  |
    380  |       /* filter junk out: leading/trailing/redundant whitespaces */
    381  |       icopy = ut_string_compress( input );
    382  |
    383  |       /* set thread accounting */
    384  |       TA_setactivity(icopy);
    385  |       TA_increment();
    386  |
    387  |       /*      if( strlen(icopy) > 0 ) {*/
    388  |       {
    389  | 	ER_inf_va(FAC_PC, ASP_PC_I_COMMAND, icopy);
    390  |
    391  | 	connected = process_input(icopy, &condat);
    392  |       }
    393  |
    394  |       TA_setactivity("");
    395  |
    396  |       free(icopy);
    397  |     }
    398  |
    399  |     /* Log admin logging off */
    400  |     ER_inf_va(FAC_PC, ASP_PC_I_SESSION,
    401  | 		"user %s from %s logged off", user, condat.ip );
    402  |
    403  |   }
    404  |
    405  |   wr_free(condat.ip);
    406  | } /* PC_interact() */
    407  |