Source File modules/pc/protocol_config.c

    1    | /***************************************
    2    |   $Revision: 1.10 $
    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   |   Author              : ottrey@ripe.net
    12   |   OSs Tested          : Solaris
    13   |   To Do               : Add a facility to take callbacks instead of
    14   |                         hard-coding menu options.
    15   |                         Add in all the menu support provided by the GLib
    16   |                         libraries.
    17   |                         (Remove strtok if multiple threads are to be used.)
    18   |   ******************/ /******************
    19   |   Copyright (c) 1999                              RIPE NCC
    20   |
    21   |   All Rights Reserved
    22   |
    23   |   Permission to use, copy, modify, and distribute this software and its
    24   |   documentation for any purpose and without fee is hereby granted,
    25   |   provided that the above copyright notice appear in all copies and that
    26   |   both that copyright notice and this permission notice appear in
    27   |   supporting documentation, and that the name of the author not be
    28   |   used in advertising or publicity pertaining to distribution of the
    29   |   software without specific, written prior permission.
    30   |
    31   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    32   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
    33   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
    34   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
    35   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    36   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    37   |   ***************************************/
    38   | #include <stdio.h>
    39   | #include <stdlib.h>
    40   | #include <unistd.h>
    41   | #include <time.h>       /* Time stuff */
    42   | #include <sys/ioctl.h>      /* Terminal control stuff */
    43   | #include <termio.h>      /* Terminal control stuff */
    44   |
    45   | #include "mysql_driver.h"
    46   | #include "constants.h"
    47   | #include "properties.h"
    48   | #include "thread.h"
    49   | #include "protocol_config.h"
    50   | #include "access_control.h"
    51   | #include "socket.h"
    52   |
    53   | /*+ Each command has a +*/
    54   | typedef struct _command {
    55   |   const char *name;                          /*+ Name to be invoked. +*/
    56   |   char *(*function)(char *, sk_conn_st *);   /*+ Function to be invoked. +*/
    57   |   const char *help;                                /*+ Command help. +*/
    58   | } Command;
    59   |
    60   | /*
    61   |  * Forward declarations
    62   |  */
    63   | static char *command_help(char *input, sk_conn_st *condat);
    64   | static char *command_quit(char *input, sk_conn_st *condat);
    65   | static char *command_show(char *input, sk_conn_st *condat);
    66   | static char *command_repeat(char *input, sk_conn_st *condat);
    67   | static char *show_const(char *input, sk_conn_st *condat);
    68   | static char *show_consts(char *input, sk_conn_st *condat);
    69   | static char *show_props(char *input, sk_conn_st *condat);
    70   | static char *show_thread(char *input, sk_conn_st *condat);
    71   | static char *show_whois(char *input, sk_conn_st *condat);
    72   | static char *show_access(char *input, sk_conn_st *condat);
    73   | static char *show_acl(char *input, sk_conn_st *condat);
    74   | static char *command_set(char *input, sk_conn_st *condat);
    75   | static char *set_const(char *input, sk_conn_st *condat);
    76   | static char *set_consts(char *input, sk_conn_st *condat);
    77   | static char *set_props(char *input, sk_conn_st *condat);
    78   | static char *command_sql(char *input, sk_conn_st *condat);
    79   |
    80   | /*+
    81   |  * Contains the command definitions
    82   | +*/
    83   | static struct _command command[] = {
    84   |   {"help"   , command_help   , HELP_HELP   },
    85   |   {"quit"   , command_quit   , HELP_QUIT   },
    86   |   {"show"   , command_show   , HELP_SHOW   },
    87   |   {"repeat" , command_repeat , HELP_REPEAT },
    88   |   {"set"    , command_set    , HELP_SET    },
    89   |   {"sql"    , command_sql    , HELP_SQL    },
    90   |   NULL
    91   | };
    92   |
    93   | /*+
    94   |  * Contains the show commands
    95   | +*/
    96   | static struct _command show[] = {
    97   |   {"const"   , show_const   , HELP_SHOW_CONST   },
    98   |   {"consts"  , show_consts  , HELP_SHOW_CONSTS  },
    99   |   {"props"   , show_props   , HELP_SHOW_PROPS   },
    100  |   {"thread"  , show_thread  , HELP_SHOW_THREAD  },
    101  |   {"whois"   , show_whois   , HELP_SHOW_WHOIS   },
    102  |   {"access"  , show_access  , HELP_SHOW_ACCESS  },
    103  |   {"acl"     , show_acl     , HELP_SHOW_ACL     },
    104  |   NULL
    105  | };
    106  |
    107  | /*+
    108  |  * Contains the set commands
    109  | +*/
    110  | static struct _command set[] = {
    111  |   {"const"  , set_const  , HELP_SET_CONST  },
    112  |   {"consts" , set_consts , HELP_SET_CONSTS },
    113  |   {"props"  , set_props  , HELP_SET_PROPS  },
    114  |   NULL
    115  | };
    116  |
    117  | static int find_command(char *comm_name, Command *comm) {
    118  |   int i, index;
    119  |   char comm_buffer[STR_L];
    120  |
    121  |   if (comm_name != NULL) {
    122  |     strcpy(comm_buffer, comm_name);
    123  |     strtok(comm_buffer, " \t");
    124  |     for (i=0, index=-1; comm[i].name != NULL; i++) {
    125  |       if ( strcmp(comm_buffer, comm[i].name) == 0) {
    126  |         index = i;
    127  |         break;
    128  |       }
    129  |     }
    130  |   }
    131  |   else {
    132  |     index = -2;
    133  |   }
    134  |
    135  |   return index;
    136  | } /* find_command() */
    137  |
    138  | static char *show_commands(Command *comm) {
    139  |   char *str;
    140  |   char help_buffer[STR_XL];
    141  |   char help_comm[STR_M];
    142  |   int i;
    143  |
    144  |   sprintf(help_buffer, " commands are:\n\n");
    145  |   i = 0;
    146  |   while (comm[i].name != NULL) {
    147  |     sprintf(help_comm, "%s\t%s\n", comm[i].name, comm[i].help);
    148  |     strcat(help_buffer, help_comm);
    149  |     i++;
    150  |   }
    151  |
    152  |   str = (char *)calloc(1, strlen(help_buffer)+1);
    153  |   strcpy(str, help_buffer);
    154  |
    155  |   return str;
    156  | } /* show_commands() */
    157  |
    158  |
    159  | /*
    160  |  * Command functions
    161  |  */
    162  | static char *command_help(char *input, sk_conn_st *condat) {
    163  |   char *str;
    164  |   char *str1;
    165  |   char output_buffer[STR_XXL];
    166  |   char *command_name;
    167  |   int index;
    168  |
    169  |   strcpy(output_buffer, "");
    170  |
    171  |   strtok(input, " \t");
    172  |   command_name = (char *)strtok(NULL, " \t");
    173  |
    174  |   index = find_command(command_name, command);
    175  |
    176  |   switch (index) {
    177  |     case -2:
    178  |       strcat(output_buffer, "Main");
    179  |       str1 = show_commands(command);
    180  |       strcat(output_buffer, str1);
    181  |       free(str1);
    182  |       break;
    183  |
    184  |     case -1:
    185  |       strcat(output_buffer, HELP_ERROR);
    186  |       strcat(output_buffer, command_name);
    187  |       break;
    188  |
    189  |     default:
    190  |       strcat(output_buffer, command[index].help);
    191  |   }
    192  |
    193  |   /*
    194  |   str = (char *)CopyString(output_buffer);
    195  |   */
    196  |   str = (char *)calloc(1, strlen(output_buffer)+1);
    197  |   strcpy(str, output_buffer);
    198  |
    199  |   return str;
    200  | } /* command_help() */
    201  |
    202  | static char *command_quit(char *input, sk_conn_st *condat) {
    203  |     /* Administrator wishes to quit. */
    204  |   return NULL;
    205  | } /* command_quit() */
    206  |
    207  | static char *show_const(char *input, sk_conn_st *condat) {
    208  |   /* Administrator wishes to show constants. */
    209  |   char *result;
    210  |   char *name;
    211  |   char *tmp_input;
    212  |
    213  |   tmp_input = (char *)calloc(1, strlen(input)+1);
    214  |   strcpy(tmp_input, input);
    215  |
    216  |   /* The name will be the third token in stuff */
    217  |   strtok(tmp_input, " ");
    218  |   strtok(NULL, " ");
    219  |   name = (char *)strtok(NULL, " ");
    220  |
    221  |   result = CO_const_to_string(name);
    222  |
    223  |   free(tmp_input);
    224  |   return result;
    225  |
    226  | } /* show_const() */
    227  |
    228  | static char *show_consts(char *input, sk_conn_st *condat) {
    229  |   /* Administrator wishes to show constants. */
    230  |   return CO_to_string();
    231  |
    232  | } /* show_consts() */
    233  |
    234  | static char *show_props(char *input, sk_conn_st *condat) {
    235  |   /* Administrator wishes to show properties. */
    236  |   return PR_to_string();
    237  |
    238  | } /* show_props() */
    239  |
    240  | static char *show_thread(char *input, sk_conn_st *condat) {
    241  |   /* Administrator wishes to show thread information. */
    242  |   return TH_to_string();
    243  |
    244  | } /* show_thread() */
    245  |
    246  | static char *show_whois(char *input, sk_conn_st *condat) {
    247  |   /* Administrator wishes to show whois query information. */
    248  |   return "WQ_to_string();";
    249  |
    250  | } /* show_whois() */
    251  |
    252  | static char *show_access(char *input, sk_conn_st *condat) {
    253  |   /* Administrator wishes to show whois query information. */
    254  |
    255  |   char line[128];
    256  |   int cnt;
    257  |   er_ret_t err;
    258  |
    259  |   if( act_runtime->top_ptr != NULL ) {
    260  |     cnt = rx_walk_tree(act_runtime->top_ptr, AC_rxwalkhook_print,
    261  | 		       RX_WALK_SKPGLU,  /* print no glue nodes */
    262  | 		       255, 0, 0, condat, &err);
    263  |     sprintf(line,"Found %d nodes\n", cnt);
    264  |     SK_cd_puts(condat,line);
    265  |   }
    266  |
    267  |   return "";
    268  |
    269  | } /* show_access() */
    270  |
    271  | static char *show_acl(char *input, sk_conn_st *condat) {
    272  |   /* Administrator wishes to show access control list. */
    273  |
    274  |   char line[128];
    275  |   int cnt;
    276  |   er_ret_t err;
    277  |
    278  |   if( act_acl->top_ptr != NULL ) {
    279  |     cnt = rx_walk_tree(act_acl->top_ptr, AC_rxwalkhook_print_acl,
    280  | 		       RX_WALK_SKPGLU,  /* print no glue nodes */
    281  | 		       255, 0, 0, condat, &err);
    282  |     sprintf(line,"Found %d nodes\n", cnt);
    283  |     SK_cd_puts(condat,line);
    284  |   }
    285  |
    286  |   return "";
    287  |
    288  | } /* show_acl() */
    289  |
    290  | static char *command_execute(char *input, char *comm_name,
    291  | 			     Command *comm, sk_conn_st *condat) {
    292  |   char *str;
    293  |   char *str1;
    294  |   char output_buffer[STR_XXL];
    295  |   char tmp[STR_L];
    296  |   char *name;
    297  |   int index;
    298  |   char *tmp_input;
    299  |
    300  |   /* Make a copy of the input */
    301  |   tmp_input = (char *)calloc(1, strlen(input)+1);
    302  |   strcpy(tmp_input, input);
    303  |
    304  |   strtok(tmp_input, " \t");
    305  |   name = (char *)strtok(NULL, " \t");
    306  |
    307  |   index = find_command(name, comm);
    308  |
    309  |   switch (index) {
    310  |     case -2:
    311  |       str1 = show_commands(comm);
    312  |       sprintf(output_buffer, "%s%s", comm_name, str1);
    313  |       free(str1);
    314  |       break;
    315  |
    316  |     case -1:
    317  |       sprintf(output_buffer, "%s invalid command: %s", comm_name, name);
    318  |       break;
    319  |
    320  |     default:
    321  |       sprintf(output_buffer, "%s", comm[index].function(input, condat));
    322  |   }
    323  |
    324  |   /*
    325  |   str = (char *)CopyString(output_buffer);
    326  |   */
    327  |   str = (char *)calloc(1, strlen(output_buffer)+1);
    328  |   strcpy(str, output_buffer);
    329  |
    330  |   free(tmp_input);
    331  |
    332  |   return str;
    333  | } /* command_execute() */
    334  |
    335  | static char *command_show(char *input, sk_conn_st *condat) {
    336  |   return command_execute(input, "Show", show, condat);
    337  | } /* command_show() */
    338  |
    339  | static char *command_repeat(char *input, sk_conn_st *condat) {
    340  |   char *command_ptr;
    341  |
    342  |   /* Goto the bit after "repeat n " */
    343  |   for (command_ptr=input+7; command_ptr[0] != ' ' || (command_ptr[0] >= '0' && command_ptr[0] <= '9'); command_ptr++);
    344  |
    345  |   return command_ptr+1;
    346  |
    347  | } /* command_show() */
    348  |
    349  | static char *set_const(char *input, sk_conn_st *condat) {
    350  |   /* Administrator wishes to set a constant. */
    351  |   char *result;
    352  |   char result_buf[STR_M];
    353  |   char *tmp_input;
    354  |   char *name;
    355  |   char *value;
    356  |   int value_len;
    357  |   char *stuff;
    358  |   char *str;
    359  |
    360  |   tmp_input = (char *)calloc(1, strlen(input)+1);
    361  |   strcpy(tmp_input, input);
    362  |
    363  |   stuff = (char *)strtok(tmp_input, "=");
    364  |
    365  |   /* The value will be after the '=' */
    366  |   value = (char *)strtok(NULL, "=");
    367  |
    368  |   /* The name will be the third token in stuff */
    369  |   strtok(stuff, " ");
    370  |   strtok(NULL, " ");
    371  |   name = (char *)strtok(NULL, " ");
    372  |
    373  |   /* Remove any quotes */
    374  |   if (value[0] == '"') {
    375  |     value++;
    376  |   }
    377  |   value_len=strlen(value);
    378  |   if (value[value_len-1] == '"') {
    379  |     value[value_len-1]='\0';
    380  |   }
    381  |
    382  |   printf("set_const name=(%s), value=(%s)\n", name, value);
    383  |   if (CO_set_const(name, value) == 0) {
    384  |     strcpy(result_buf, "Constant successfully set\n");
    385  |   }
    386  |   else {
    387  |     str = CO_const_to_string(name);
    388  |     sprintf(result_buf, "Constant not successfully set\nReverting to:   %s=%s\n", name, str);
    389  |     free(str);
    390  |   }
    391  |
    392  |   result = (char *)calloc(1, strlen(result_buf)+1);
    393  |   strcpy(result, result_buf);
    394  |
    395  |   free(tmp_input);
    396  |   return result;
    397  | } /* set_const() */
    398  |
    399  | static char *set_consts(char *input, sk_conn_st *condat) {
    400  |   /* Administrator wishes to set constants. */
    401  |   return CO_set();
    402  | } /* set_consts() */
    403  |
    404  | static char *set_props(char *input, sk_conn_st *condat) {
    405  |   /* Administrator wishes to set properties. */
    406  |   return PR_set();
    407  | } /* set_props() */
    408  |
    409  | static char *command_set(char *input, sk_conn_st *condat) {
    410  |   return command_execute(input, "Set", set, condat);
    411  | } /* command_set() */
    412  |
    413  | static char *command_sql(char *input, sk_conn_st *condat) {
    414  |   char *str;
    415  |   char output_buffer[STR_XXL];
    416  |   char *current_character;
    417  |   char *whois_query;
    418  |   char *sql_str;
    419  |
    420  |   char *res=NULL;
    421  |
    422  |   SQ_result_set_t *sql_result=NULL;
    423  |   SQ_connection_t *sql_connection;
    424  |
    425  |   sql_connection = SQ_get_connection(CO_get_host(), CO_get_database_port(), CO_get_database(), CO_get_user(), CO_get_password() );
    426  |
    427  |   if (sql_connection == NULL) {
    428  |     printf("/* Check for errors */\n");
    429  |   }
    430  |
    431  |   /* skip over the "sql" */
    432  |   sql_str = input+3;
    433  |   /* skip over white space */
    434  |   while (sql_str[0] == ' ') {
    435  |     sql_str++;
    436  |   }
    437  |
    438  |   strcpy(output_buffer, "");
    439  |
    440  |   if (sql_connection != NULL) {
    441  |     if (strcmp(sql_str, "status") == 0) {
    442  |       /* Get the status of the database */
    443  |       res = SQ_info_to_string(sql_connection);
    444  |     }
    445  |     else {
    446  |       if (strcmp(sql_str, "") == 0) {
    447  |         /* Execute the default query (from the properties file) */
    448  |         sql_result = SQ_execute_query(SQ_STORE, sql_connection, CO_get_query());
    449  |       }
    450  |       else {
    451  |         /* Execute an sql query */
    452  |         sql_result = SQ_execute_query(SQ_STORE, sql_connection, sql_str);
    453  |       }
    454  |       if (sql_result != NULL) {
    455  |         res = SQ_result_to_string(sql_result);
    456  |       }
    457  |       else {
    458  |         printf("no results\n");
    459  |       }
    460  |     }
    461  |     if (res != NULL) {
    462  |       sprintf(output_buffer, "%s", res);
    463  |     }
    464  |     else {
    465  |       printf("empty results\n");
    466  |     }
    467  |   }
    468  |   else {
    469  |     printf("Failed to make connection\n");
    470  |   }
    471  |
    472  |   /*
    473  |   strcat(output_buffer, mysql_info(sql_connection));
    474  |   */
    475  |
    476  |   strcat(output_buffer, "XXX Results from mysql_info(sql_connection) is meant to go here.  But it's not working!");
    477  |
    478  |   /*
    479  |   str = (char *)CopyString(output_buffer);
    480  |   */
    481  |   str = (char *)calloc(1, strlen(output_buffer)+1);
    482  |   strcpy(str, output_buffer);
    483  |
    484  |   free(res);
    485  |   SQ_free_result(sql_result);
    486  |
    487  |   SQ_close_connection(sql_connection);
    488  |
    489  |   return str;
    490  |
    491  | } /* command_sql() */
    492  |
    493  |
    494  | /* process_input() */
    495  | /*++++++++++++++++++++++++++++++++++++++
    496  |
    497  |   Process the input.
    498  |
    499  |   sk_conn_st *condat         connection data
    500  |
    501  |   More:
    502  |   +html+ <PRE>
    503  |   Author:
    504  |         ottrey
    505  |   +html+ </PRE>
    506  |   ++++++++++++++++++++++++++++++++++++++*/
    507  | static int process_input(char *input, sk_conn_st *condat) {
    508  |   int connected = 1;
    509  |   char *input_ptr;
    510  |   char *output;
    511  |   char *command_name;
    512  |   int  index;
    513  |   int repeat=0;
    514  |
    515  |   input_ptr = input;
    516  |
    517  |   if (strncmp(input, "repeat", 6) == 0) {
    518  |     /* XXX This is a really dodgy call, that hopefully converts
    519  |     the string to the value of the first found integer. */
    520  |     repeat = atoi(input+7);
    521  |     input_ptr= command_repeat(input, condat);
    522  |   }
    523  |
    524  |   index = find_command(input_ptr, command);
    525  |
    526  |   do {
    527  |     switch (index) {
    528  |       case -1:
    529  |         /* Command not found */
    530  |         output = command_help(NULL, condat);
    531  |         break;
    532  |
    533  |       default:
    534  |         output = command[index].function(input_ptr, condat);
    535  |     }
    536  |
    537  |     if(output == NULL) {
    538  |       connected = 0;
    539  |     } else {
    540  |       /*
    541  |       printf("thread output=\n%s\n", output);
    542  |       */
    543  |       if ( CO_get_clear_screen() == 1 ) {
    544  |         SK_cd_puts(condat, CLEAR_SCREEN);
    545  |       }
    546  |       SK_cd_puts(condat,  output);
    547  |       SK_cd_puts(condat, "\n");
    548  |       SK_cd_puts(condat, CO_get_prompt());
    549  |     }
    550  |
    551  |     free(output);
    552  |
    553  |     if (repeat > 0) {
    554  |       repeat--;
    555  |       sleep(CO_get_sleep_time());
    556  |     }
    557  |
    558  |   } while (repeat > 0);
    559  |
    560  |   return connected;
    561  |
    562  | } /* process_input() */
    563  |
    564  | static void log_config(const char *user, const char *status) {
    565  |   FILE *logf;
    566  |   char *str;
    567  |   time_t now;
    568  |
    569  |   time(&now);
    570  |
    571  |   if (CO_get_config_logging() == 1) {
    572  |
    573  |     if (strcmp(CO_get_config_logfile(), "stdout") == 0) {
    574  |       printf(LOG_CONFIG, TH_get_id(), user, status, ctime(&now));
    575  |     }
    576  |     else {
    577  |       logf = fopen(CO_get_config_logfile(), "a");
    578  |       fprintf(logf, LOG_CONFIG, TH_get_id(), user, status, ctime(&now));
    579  |       fclose(logf);
    580  |     }
    581  |   }
    582  |
    583  | } /* log_config() */
    584  |
    585  | /* XXX Doh! These only change the server's terminal.  We need some
    586  |    tricky escape sequence to send over the socket. */
    587  | static void echo_off(int sock) {
    588  |   struct termio state;
    589  |
    590  |   ioctl(0, TIOCGETP, &state);
    591  |   state.c_lflag &= ~ECHO;
    592  |   ioctl(0, TIOCSETP, &state);
    593  | } /* echo_off() */
    594  |
    595  | /* XXX Doh! These only change the server's terminal.  We need some
    596  |    tricky escape sequence to send over the socket. */
    597  | static void echo_on(int sock) {
    598  |   struct termio state;
    599  |
    600  |   ioctl(0, TIOCGETP, &state);
    601  |   state.c_lflag |= ECHO;
    602  |   ioctl(0, TIOCSETP, &state);
    603  | } /* echo_on() */
    604  |
    605  | static char *authenticate_user(sk_conn_st *condat) {
    606  |   char *user = NULL;
    607  |   char Salt[2] = "DB";
    608  |   char input[MAX_INPUT_SIZE];
    609  |   int read_result;
    610  |   char *password=NULL;
    611  |   char *user_password=NULL;
    612  |   char user_buf[10];
    613  |
    614  |   SK_cd_puts(condat, LOGIN_PROMPT);
    615  |   read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE);
    616  |
    617  |   strncpy(user_buf, input, 10);
    618  |
    619  |   SK_cd_puts(condat, PASSWD_PROMPT);
    620  |   /* XXX These aren't working.
    621  |   SK_puts(sock, ECHO_ON);
    622  |   echo_off(sock);
    623  |   */
    624  |   read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE);
    625  |   /* XXX These aren't working.
    626  |   echo_on(sock);
    627  |   SK_puts(sock, ECHO_OFF);
    628  |   */
    629  |
    630  |   password = (char *)crypt(input, Salt);
    631  |
    632  |   user_password = PR_get_property(user_buf, DEFAULT_USER_NAME);
    633  |
    634  |   if (user_password != NULL) {
    635  |     if (strcmp(password, user_password) == 0) {
    636  |       user = (char *)calloc(1, strlen(user_buf)+1);
    637  |       strcpy(user, user_buf);
    638  |     }
    639  |   }
    640  |
    641  |   if (user == NULL) {
    642  |     log_config(user_buf, "unsuccesful login attempt");
    643  |   }
    644  |
    645  |   return user;
    646  |
    647  | } /* authenticate_user() */
    648  |
    649  | void PC_interact(int sock) {
    650  |   char input[MAX_INPUT_SIZE];
    651  |   int connected = 1;
    652  |   int read_result;
    653  |   char *welcome;
    654  |   char *user=NULL;
    655  |   sk_conn_st condat;
    656  |
    657  |   memset( &condat, 0, sizeof(condat));
    658  |   condat.sock = sock;
    659  |   SK_getpeerip(sock, &(condat.rIP));
    660  |   condat.ip = SK_getpeername(sock);
    661  |
    662  |   /* Welcome the client */
    663  |   SK_cd_puts(&condat, CO_get_welcome());
    664  |
    665  |   /* Authenticate the user */
    666  |   if (CO_get_authenticate() == 1) {
    667  |     user = authenticate_user(&condat);
    668  |   }
    669  |   else {
    670  |     user="nobody";
    671  |   }
    672  |
    673  |   if (user != NULL) {
    674  |     /* Log admin logging on */
    675  |     log_config(user, "logged on");
    676  |
    677  |     SK_cd_puts(&condat, CO_get_prompt());
    678  |
    679  |     while (condat.rtc==0 && connected) {
    680  |       /* Read input */
    681  |       SK_cd_gets(&condat, input, MAX_INPUT_SIZE);
    682  |       connected = process_input(input, &condat);
    683  |     }
    684  |
    685  |     /* Log admin logging off */
    686  |     log_config(user, "logged off");
    687  |   }
    688  |
    689  |   /* Close the socket */
    690  |   SK_close(sock);
    691  |
    692  | } /* PC_interact() */
    693  |