## 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_execute
4. process_input
5. authenticate_user
6. PC_interact

       1 /***************************************
       2   $Revision: 1.39 $
       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,2000,2001,2002               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
      41 #define PC_IMPL
      42 #include "rip.h"
      43
      44 #include <stdio.h>
      45 #include <stdlib.h>
      46 #include <time.h>
      47 #include <sys/ioctl.h>
      48 #include <glib.h>
      49
      50 /*+ Maximum size of input that can be recieved from the client. +*/
      51 #define MAX_INPUT_SIZE  1024
      52
      53 extern char* crypt(const char *, const char *);   /* crypt stuff */
      54
      55
      56 /*++++++++++++++++++++++++++++++++++++++
      57
      58   Finds a command by name in the array of command function structures.
      59
      60   int find_command     returns the index to the correct row of the array, or -1
      61                        if the command could not be found.
      62
      63   char *comm_name      name of the command
      64
      65   Command *comm        array of command function structures.
      66   ++++++++++++++++++++++++++++++++++++++*/
      67 static
      68 int find_command(char *comm_name, Command *comm)
         /* [<][>][^][v][top][bottom][index][help] */
      69 {
      70   int i;
      71   char *comm_buffer = wr_string(comm_name);
      72   char *token, *cursor;
      73   int index = -1;
      74
      75   cursor = comm_buffer;
      76   if( (token = strsep(&cursor, " \t")) != NULL) {
      77     for (i=0; comm[i].name != NULL; i++) {
      78       if ( strcmp(token, comm[i].name) == 0) {
      79         index = i;
      80         break;
      81       }
      82     }
      83   }
      84
      85   UT_free(comm_buffer);
      86
      87   return index; /* returns -1 when command not found */
      88 } /* find_command() */
      89
      90
      91 int show_commands(Command *comm, char *comm_name, GString *output)
         /* [<][>][^][v][top][bottom][index][help] */
      92 {
      93   int i = 0;
      94
      95   g_string_sprintfa(output, "%scommands are:\n\n", comm_name);
      96   while (comm[i].name != NULL) {
      97     g_string_sprintfa(output, "%s\t%s\n", comm[i].name, comm[i].help);
      98     i++;
      99   }
     100
     101   return 1;
     102 } /* show_commands() */
     103
     104
     105 /*++++++++++++++++++++++++++++++++++++++
     106
     107   int command_execute
     108                       executes a command from the given array, matching
     109                       given name. Passes input, output and condat to the
     110                       function found in the array. Command name is
     111                       removed from the input line so only next words are
     112                       passed over to the function.
     113
     114                       returns the code of the last command. Code
     115                       PC_RET_QUIT is reserved to indicate that the connection
     116                       should be closed.
     117
     118   Command *comm       array of command function structures (defined in
     119                       protocol_config.h)
     120
     121   char *comm_name     name of the command to be run
     122
     123   char *input         rest of the command line
     124
     125   GString *output     dynamically built output string
     126
     127   sk_conn_st *condat  socket structure for this connection (some commands
     128                       use it directly instead of storing the output)
     129
     130   ++++++++++++++++++++++++++++++++++++++*/
     131 int command_execute(Command *comm, char *comm_name,
         /* [<][>][^][v][top][bottom][index][help] */
     132                     char *input, GString *output, sk_conn_st *condat)
     133 {
     134   char *name, *next_word, *tmp_input;
     135   int index, result=0;
     136
     137   /* find the command in the string - first whitespace delimited word */
     138   /* make a copy of the input */
     139   dieif( (tmp_input = wr_string(input)) == NULL );
     140   next_word = tmp_input;
     141
     142   /* find the first word and set the pointer to the rest of the string */
     143   name = strsep(&next_word, " \t");
     144
     145   if( name != NULL && strlen(name) != 0 ) {
     146     index = find_command(name, comm);
     147     if( index != -1 ) {
     148       if( next_word != NULL ) {
     149         /* advance the input pointer to the next word */
     150         while(  *next_word != '\0'
     151                 && isspace( *(unsigned char *)next_word) ) {
     152           next_word++;
     153         }
     154       }
     155       else {
     156         next_word = "";
     157       }
     158
     159       /* run, Forrest, run...*/
     160       result = comm[index].function(next_word, output, condat);
     161     }
     162     else {
     163       g_string_sprintfa(output, "invalid %scommand: %s\n", comm_name, name);
     164       show_commands(comm, comm_name, output);
     165       result = 2;
     166     }
     167   }
     168   else {
     169     show_commands(comm, comm_name, output);
     170     result = 2;
     171   }
     172
     173   UT_free(tmp_input);
     174
     175   return result;
     176 } /* command_execute() */
     177
     178
     179
     180
     181
     182
     183
     184 /* proces_input() */
     185 /*++++++++++++++++++++++++++++++++++++++
     186
     187   Process the input. Finds the proper command in the top level command
     188   array and invokes the function associated with it with the input and
     189   output data as arguments.
     190
     191   int process_input          returns 1 if the connection is to be kept
     192                              or 0 when it should be finished - that is,
     193                              when command_execute() returns PC_RET_QUIT.
     194
     195   char *input                input (presumably a command)
     196
     197   sk_conn_st *condat         connection data
     198
     199   More:
     200   +html+ <PRE>
     201   Author:
     202         ottrey
     203         marek - changes and documentation.
     204   +html+ </PRE>
     205   ++++++++++++++++++++++++++++++++++++++*/
     206 static
     207 int process_input(char *input, sk_conn_st *condat)
         /* [<][>][^][v][top][bottom][index][help] */
     208 {
     209   int  index;
     210   int res=0;
     211   GString *output = g_string_new("");
     212
     213   index = find_command(input, command);
     214
     215   switch (index) {
     216   case -1:
     217     /* Command not found */
     218     command_help(NULL, output, condat);
     219     break;
     220
     221   default:
     222     res = command_execute(command, "", input, output, condat);
     223   }
     224
     225   if(res != PC_RET_QUIT) {
     226     /*
     227       printf("thread output=\n%s\n", output);
     228     */
     229     if ( CO_get_clear_screen() == 1 ) {
     230       SK_cd_puts(condat, CLEAR_SCREEN);
     231     }
     232     SK_cd_puts(condat,  output->str);
     233     SK_cd_printf(condat, "\n\n=%d= %s", res, CO_get_prompt());
     234
     235   }
     236
     237   g_string_free( output, TRUE );
     238
     239   /* the return value is the connection state: 1=still open, 0=to be closed
     240    */
     241
     242   return (res != PC_RET_QUIT);
     243 } /* process_input() */
     244
     245
     246 /*++++++++++++++++++++++++++++++++++++++
     247
     248   Authenticates the user - asks for password and checks it. The password is
     249   echoed by the tcp stack, to disable that one would have to attach a tty
     250   to this connection and switch to raw mode or try the hard way - renegotiate
     251   the telnet connection to switch to character mode (and, possibly, back).
     252   The latter has the drawback that to do it right it has to be able to check
     253   whether there's telnet on the other side - otherwise, if the connection
     254   is made by a program just connecting to the socket, garbage will result.
     255   However, in such case password checking might be not a good idea.
     256
     257   sk_conn_st *condat
     258
     259   More:
     260   +html+ <PRE>
     261   Author:
     262         ottrey
     263         marek - slight changes and documentation.
     264   +html+ </PRE>
     265   ++++++++++++++++++++++++++++++++++++++*/
     266 static
     267 char *authenticate_user(sk_conn_st *condat)
         /* [<][>][^][v][top][bottom][index][help] */
     268 {
     269   char *user = NULL;
     270   const char Salt[2] = "DB";
     271   char input[MAX_INPUT_SIZE];
     272   int read_result;
     273   char *password=NULL;
     274   char *user_password=NULL;
     275   char user_buf[10];
     276
     277   SK_cd_puts(condat, LOGIN_PROMPT);
     278   read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE);
     279
     280   strncpy(user_buf, input, 10);
     281
     282   SK_cd_puts(condat, PASSWD_PROMPT);
     283   /* XXX These aren't working.
     284   SK_puts(sock, ECHO_ON);
     285   echo_off(sock);
     286   */
     287   read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE);
     288   /* XXX These aren't working.
     289   echo_on(sock);
     290   SK_puts(sock, ECHO_OFF);
     291   */
     292
     293   password = crypt(input, Salt);
     294
     295   user_password = PR_get_property(user_buf, DEFAULT_USER_NAME);
     296
     297   if (user_password != NULL) {
     298     if (strcmp(password, user_password) == 0) {
     299       user = UT_strdup(user_buf);
     300     }
     301   }
     302
     303
     304   return user;
     305
     306 } /* authenticate_user() */
     307
     308
     309
     310 /*++++++++++++++++++++++++++++++++++++++
     311
     312   Main function that talks to the user connected on the given socket.
     313   Starts by authenticating the user (if this mode is active)
     314   and greeting her with the uptime data. Then it loops reading and executing
     315   commands until the "quit" command (or any other command that causes
     316   process_input to return 0).
     317
     318   int sock        connected client socket
     319
     320   ++++++++++++++++++++++++++++++++++++++*/
     321 void PC_interact(int sock) {
         /* [<][>][^][v][top][bottom][index][help] */
     322   char input[MAX_INPUT_SIZE];
     323   int connected = 1;
     324   char *user=NULL;
     325   sk_conn_st condat;
     326
     327   memset( &condat, 0, sizeof(condat));
     328   condat.sock = sock;
     329   SK_getpeerip(sock, &(condat.rIP));
     330   condat.ip = SK_getpeername(sock); /* XXX *alloc involved */
     331
     332   /* Welcome the client */
     333   SK_cd_puts(&condat, CO_get_welcome());
     334
     335   /* Authenticate the user */
     336   if (CO_get_authenticate() == 1) {
     337     user = authenticate_user(&condat);
     338
     339     if (user == NULL) {
     340       ER_inf_va(FAC_PC, ASP_PC_I_SESSION,
     341                 "unsuccesful login attempt from %s", condat.ip );
     342     }
     343   }
     344   else {
     345     user="nobody";
     346   }
     347
     348   if (user != NULL) {
     349
     350     /* Log admin logging on */
     351     ER_inf_va(FAC_PC, ASP_PC_I_SESSION,
     352                 "user %s from %s logged on", user, condat.ip );
     353
     354     {
     355       show_uptime("", NULL, &condat);
     356     }
     357
     358     SK_cd_printf(&condat, "=0= %s", CO_get_prompt());
     359
     360     while (condat.rtc==0 && connected) {
     361       char *icopy;
     362
     363       /* Read input. Quit if no input (socket closed) */
     364       if( SK_cd_gets(&condat, input, MAX_INPUT_SIZE) <= 0 ) {
     365         break;
     366       }
     367
     368       /* filter junk out: leading/trailing/redundant whitespaces */
     369       icopy = ut_string_compress( input );
     370
     371       /* set thread accounting */
     372       TA_setactivity(icopy);
     373       TA_increment();
     374
     375       /*      if( strlen(icopy) > 0 ) {*/
     376       {
     377         ER_inf_va(FAC_PC, ASP_PC_I_COMMAND, icopy);
     378
     379         connected = process_input(icopy, &condat);
     380       }
     381
     382       TA_setactivity("");
     383
     384       UT_free(icopy);
     385     }
     386
     387     /* Log admin logging off */
     388     ER_inf_va(FAC_PC, ASP_PC_I_SESSION,
     389                 "user %s from %s logged off", user, condat.ip );
     390
     391   }
     392
     393   UT_free(condat.ip);
     394 } /* PC_interact() */
     395

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