1    | /***************************************
2    |   $Revision: 1.12 $
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>     /* crypt stuff */
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     , NULL           , 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      , NULL         , 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     , NULL       , 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  |   dieif( wr_malloc((void **)&str, strlen(help_buffer)+1) != UT_OK);  
154  |   strcpy(str, help_buffer);
155  | 
156  |   return str;
157  | } /* show_commands() */
158  | 
159  | 
160  | /*
161  |  * Command functions
162  |  */
163  | static char *command_help(char *input, sk_conn_st *condat) {
164  |   char *str;
165  |   char *str1;
166  |   char output_buffer[STR_XXL];
167  |   char *command_name;
168  |   int index;
169  | 
170  |   strcpy(output_buffer, "");
171  | 
172  |   strtok(input, " \t");
173  |   command_name = (char *)strtok(NULL, " \t");
174  | 
175  |   index = find_command(command_name, command);
176  | 
177  |   switch (index) {
178  |     case -2:
179  |       strcat(output_buffer, "Main");
180  |       str1 = show_commands(command);
181  |       strcat(output_buffer, str1);
182  |       wr_free(str1);
183  |       break;
184  | 
185  |     case -1:
186  |       strcat(output_buffer, HELP_ERROR);
187  |       strcat(output_buffer, command_name);
188  |       break;
189  | 
190  |     default: 
191  |       strcat(output_buffer, command[index].help);
192  |   }
193  | 
194  |   /*
195  |   str = (char *)CopyString(output_buffer);
196  |   */
197  |   //  str = (char *)calloc(1, strlen(output_buffer)+1);
198  |   dieif( wr_malloc((void **)&str, strlen(output_buffer)+1) != UT_OK);  
199  |   strcpy(str, output_buffer);
200  | 
201  |   return str;
202  | } /* command_help() */
203  | 
204  | static char *command_quit(char *input, sk_conn_st *condat) {
205  |     /* Administrator wishes to quit. */
206  |   return NULL;
207  | } /* command_quit() */
208  | 
209  | static char *show_const(char *input, sk_conn_st *condat) {
210  |   /* Administrator wishes to show constants. */
211  |   char *result;
212  |   char *name;
213  |   char *tmp_input;
214  | 
215  |   //  tmp_input = (char *)calloc(1, strlen(input)+1);
216  |   dieif( wr_malloc((void **)&tmp_input, strlen(input)+1) != UT_OK);  
217  |   strcpy(tmp_input, input);
218  | 
219  |   /* The name will be the third token in stuff */
220  |   strtok(tmp_input, " ");
221  |   strtok(NULL, " ");
222  |   name = (char *)strtok(NULL, " ");
223  | 
224  |   result = CO_const_to_string(name);
225  | 
226  |   wr_free(tmp_input);
227  |   return result;
228  | 
229  | } /* show_const() */
230  | 
231  | static char *show_consts(char *input, sk_conn_st *condat) {
232  |   /* Administrator wishes to show constants. */
233  |   return CO_to_string();
234  | 
235  | } /* show_consts() */
236  | 
237  | static char *show_props(char *input, sk_conn_st *condat) {
238  |   /* Administrator wishes to show properties. */
239  |   return PR_to_string();
240  | 
241  | } /* show_props() */
242  | 
243  | static char *show_thread(char *input, sk_conn_st *condat) {
244  |   /* Administrator wishes to show thread information. */
245  |   return TH_to_string();
246  | 
247  | } /* show_thread() */
248  | 
249  | static char *show_whois(char *input, sk_conn_st *condat) {
250  |   /* Administrator wishes to show whois query information. */
251  |   return "WQ_to_string();";
252  | 
253  | } /* show_whois() */
254  | 
255  | static char *show_access(char *input, sk_conn_st *condat) {
256  |   /* Administrator wishes to show whois query information. */
257  |   
258  |   char line[128];
259  |   int cnt;
260  |   er_ret_t err; 
261  | 
262  |   if( act_runtime->top_ptr != NULL ) {
263  |     cnt = rx_walk_tree(act_runtime->top_ptr, AC_rxwalkhook_print, 
264  | 		       RX_WALK_SKPGLU,  /* print no glue nodes */
265  | 		       255, 0, 0, condat, &err);
266  |     sprintf(line,"Found %d nodes\n", cnt);
267  |     SK_cd_puts(condat,line);
268  |   }
269  |   
270  |   return "";
271  | 
272  | } /* show_access() */
273  | 
274  | static char *show_acl(char *input, sk_conn_st *condat) {
275  |   /* Administrator wishes to show access control list. */
276  |   
277  |   char line[128];
278  |   int cnt;
279  |   er_ret_t err; 
280  | 
281  |   if( act_acl->top_ptr != NULL ) {
282  |     cnt = rx_walk_tree(act_acl->top_ptr, AC_rxwalkhook_print_acl, 
283  | 		       RX_WALK_SKPGLU,  /* print no glue nodes */
284  | 		       255, 0, 0, condat, &err);
285  |     sprintf(line,"Found %d nodes\n", cnt);
286  |     SK_cd_puts(condat,line);
287  |   }
288  |   
289  |   return "";
290  | 
291  | } /* show_acl() */
292  | 
293  | static char *command_execute(char *input, char *comm_name, 
294  | 			     Command *comm, sk_conn_st *condat) {
295  |   char *str;
296  |   char *str1;
297  |   char output_buffer[STR_XXL];
298  |   char *name;
299  |   int index;
300  |   char *tmp_input;
301  | 
302  |   /* Make a copy of the input */
303  |   //  tmp_input = (char *)calloc(1, strlen(input)+1);
304  |   dieif( wr_malloc((void **)&tmp_input, strlen(input)+1) != UT_OK);  
305  |   strcpy(tmp_input, input);
306  | 
307  |   strtok(tmp_input, " \t");
308  |   name = (char *)strtok(NULL, " \t");
309  | 
310  |   index = find_command(name, comm);
311  | 
312  |   switch (index) {
313  |     case -2:
314  |       str1 = show_commands(comm);
315  |       sprintf(output_buffer, "%s%s", comm_name, str1);
316  |       wr_free(str1);
317  |       break;
318  | 
319  |     case -1:
320  |       sprintf(output_buffer, "%s invalid command: %s", comm_name, name);
321  |       break;
322  | 
323  |     default: 
324  |       sprintf(output_buffer, "%s", comm[index].function(input, condat));
325  |   }
326  | 
327  |   /*
328  |   str = (char *)CopyString(output_buffer);
329  |   */
330  |   //  str = (char *)calloc(1, strlen(output_buffer)+1);
331  |   dieif( wr_malloc((void **)&str, strlen(output_buffer)+1) != UT_OK);  
332  |   strcpy(str, output_buffer);
333  | 
334  |   wr_free(tmp_input);
335  | 
336  |   return str;
337  | } /* command_execute() */
338  | 
339  | static char *command_show(char *input, sk_conn_st *condat) {
340  |   return command_execute(input, "Show", show, condat);
341  | } /* command_show() */
342  | 
343  | static char *command_repeat(char *input, sk_conn_st *condat) {
344  |   char *command_ptr;
345  | 
346  |   /* Goto the bit after "repeat n " */
347  |   for (command_ptr=input+7; command_ptr[0] != ' ' || (command_ptr[0] >= '0' && command_ptr[0] <= '9'); command_ptr++);
348  | 
349  |   return command_ptr+1;
350  | 
351  | } /* command_show() */
352  | 
353  | static char *set_const(char *input, sk_conn_st *condat) {
354  |   /* Administrator wishes to set a constant. */
355  |   char *result;
356  |   char result_buf[STR_M];
357  |   char *tmp_input;
358  |   char *name;
359  |   char *value;
360  |   int value_len;
361  |   char *stuff;
362  |   char *str;
363  | 
364  |   //  tmp_input = (char *)calloc(1, strlen(input)+1);
365  |   dieif( wr_malloc((void **)&tmp_input, strlen(input)+1) != UT_OK);  
366  |   strcpy(tmp_input, input);
367  | 
368  |   stuff = (char *)strtok(tmp_input, "=");
369  | 
370  |   /* The value will be after the '=' */
371  |   value = (char *)strtok(NULL, "=");
372  | 
373  |   /* The name will be the third token in stuff */
374  |   strtok(stuff, " ");
375  |   strtok(NULL, " ");
376  |   name = (char *)strtok(NULL, " ");
377  | 
378  |   /* Remove any quotes */
379  |   if (value[0] == '"') {
380  |     value++;
381  |   }
382  |   value_len=strlen(value);
383  |   if (value[value_len-1] == '"') {
384  |     value[value_len-1]='\0';
385  |   }
386  | 
387  |   printf("set_const name=(%s), value=(%s)\n", name, value);
388  |   if (CO_set_const(name, value) == 0) {
389  |     strcpy(result_buf, "Constant successfully set\n");
390  |   }
391  |   else {
392  |     str = CO_const_to_string(name);
393  |     sprintf(result_buf, "Constant not successfully set\nReverting to:   %s=%s\n", name, str);
394  |     wr_free(str);
395  |   }
396  | 
397  |   //  result = (char *)calloc(1, strlen(result_buf)+1);
398  |   dieif( wr_malloc((void **)&result, strlen(result_buf)+1) != UT_OK);  
399  |   strcpy(result, result_buf);
400  | 
401  |   wr_free(tmp_input);
402  |   return result;
403  | } /* set_const() */
404  | 
405  | static char *set_consts(char *input, sk_conn_st *condat) {
406  |   /* Administrator wishes to set constants. */
407  |   return CO_set();
408  | } /* set_consts() */
409  | 
410  | static char *set_props(char *input, sk_conn_st *condat) {
411  |   /* Administrator wishes to set properties. */
412  |   return PR_set();
413  | } /* set_props() */
414  | 
415  | static char *command_set(char *input, sk_conn_st *condat) {
416  |   return command_execute(input, "Set", set, condat);
417  | } /* command_set() */
418  | 
419  | static char *command_sql(char *input, sk_conn_st *condat) {
420  |   char *str;
421  |   char output_buffer[STR_XXL];
422  |   char *sql_str;
423  | 
424  |   char *res=NULL;
425  | 
426  |   SQ_result_set_t *sql_result=NULL;
427  |   SQ_connection_t *sql_connection;
428  | 
429  |   sql_connection = SQ_get_connection(CO_get_host(), CO_get_database_port(), CO_get_database(), CO_get_user(), CO_get_password() );
430  | 
431  |   if (sql_connection == NULL) {
432  |     printf("/* Check for errors */\n");
433  |   }
434  | 
435  |   /* skip over the "sql" */
436  |   sql_str = input+3;
437  |   /* skip over white space */
438  |   while (sql_str[0] == ' ') {
439  |     sql_str++;
440  |   }
441  | 
442  |   strcpy(output_buffer, "");
443  | 
444  |   if (sql_connection != NULL) {
445  |     if (strcmp(sql_str, "status") == 0) {
446  |       /* Get the status of the database */
447  |       res = SQ_info_to_string(sql_connection);
448  |     }
449  |     else {
450  |       if (strcmp(sql_str, "") == 0) {
451  |         /* Execute the default query (from the properties file) */
452  |         sql_result = SQ_execute_query(SQ_STORE, sql_connection, CO_get_query());
453  |       }
454  |       else {
455  |         /* Execute an sql query */
456  |         sql_result = SQ_execute_query(SQ_STORE, sql_connection, sql_str);
457  |       }
458  |       if (sql_result != NULL) {
459  |         res = SQ_result_to_string(sql_result);
460  |       }
461  |       else {
462  |         printf("no results\n");
463  |       }
464  |     }
465  |     if (res != NULL) {
466  |       sprintf(output_buffer, "%s", res);
467  |     }
468  |     else {
469  |       printf("empty results\n");
470  |     }
471  |   }
472  |   else {
473  |     printf("Failed to make connection\n");
474  |   }
475  | 
476  |   /*
477  |   strcat(output_buffer, mysql_info(sql_connection));
478  |   */
479  | 
480  |   strcat(output_buffer, "XXX Results from mysql_info(sql_connection) is meant to go here.  But it's not working!");
481  | 
482  |   /*
483  |   str = (char *)CopyString(output_buffer);
484  |   */
485  |   //  str = (char *)calloc(1, strlen(output_buffer)+1);
486  |   dieif( wr_malloc((void **)&str, strlen(output_buffer)+1) != UT_OK);  
487  |   strcpy(str, output_buffer);
488  | 
489  |   wr_free(res);
490  |   SQ_free_result(sql_result);
491  | 
492  |   SQ_close_connection(sql_connection);
493  | 
494  |   return str;
495  | 
496  | } /* command_sql() */
497  | 
498  | 
499  | /* process_input() */
500  | /*++++++++++++++++++++++++++++++++++++++
501  | 
502  |   Process the input.
503  | 
504  |   sk_conn_st *condat         connection data    
505  | 
506  |   More:
507  |   +html+ <PRE>
508  |   Author:
509  |         ottrey
510  |   +html+ </PRE>
511  |   ++++++++++++++++++++++++++++++++++++++*/
512  | static int process_input(char *input, sk_conn_st *condat) {
513  |   int connected = 1;
514  |   char *input_ptr;
515  |   char *output;
516  |   int  index;
517  |   int repeat=0;
518  | 
519  |   input_ptr = input;
520  | 
521  |   if (strncmp(input, "repeat", 6) == 0) {
522  |     /* XXX This is a really dodgy call, that hopefully converts
523  |     the string to the value of the first found integer. */
524  |     repeat = atoi(input+7);
525  |     input_ptr= command_repeat(input, condat);
526  |   }
527  | 
528  |   index = find_command(input_ptr, command);
529  | 
530  |   do {
531  |     switch (index) {
532  |       case -1:
533  |         /* Command not found */
534  |         output = command_help(NULL, condat);
535  |         break;
536  | 
537  |       default: 
538  |         output = command[index].function(input_ptr, condat);
539  |     }
540  | 
541  |     if(output == NULL) {
542  |       connected = 0;
543  |     } else {
544  |       /*
545  |       printf("thread output=\n%s\n", output);
546  |       */
547  |       if ( CO_get_clear_screen() == 1 ) {
548  |         SK_cd_puts(condat, CLEAR_SCREEN);
549  |       }
550  |       SK_cd_puts(condat,  output);
551  |       SK_cd_puts(condat, "\n");
552  |       SK_cd_puts(condat, CO_get_prompt());
553  |       
554  |       wr_free(output);
555  |     }
556  | 
557  |     if (repeat > 0) {
558  |       repeat--;
559  |       sleep(CO_get_sleep_time());
560  |     }
561  | 
562  |   } while (repeat > 0);
563  | 
564  |   return connected;
565  | 
566  | } /* process_input() */
567  | 
568  | static void log_config(const char *user, const char *status) {
569  |   FILE *logf;
570  |   time_t now;
571  | 
572  |   time(&now);
573  | 
574  |   if (CO_get_config_logging() == 1) {
575  |     
576  |     if (strcmp(CO_get_config_logfile(), "stdout") == 0) {
577  |       printf(LOG_CONFIG, TH_get_id(), user, status, ctime(&now));
578  |     }
579  |     else {
580  |       logf = fopen(CO_get_config_logfile(), "a");
581  |       fprintf(logf, LOG_CONFIG, TH_get_id(), user, status, ctime(&now));
582  |       fclose(logf);
583  |     }
584  |   }
585  | 
586  | } /* log_config() */
587  |  
588  | /* XXX Doh! These only change the server's terminal.  We need some
589  |    tricky escape sequence to send over the socket.
590  | static void echo_off(int sock) {
591  |   struct termio state;
592  | 
593  |   ioctl(0, TIOCGETP, &state);
594  |   state.c_lflag &= ~ECHO;
595  |   ioctl(0, TIOCSETP, &state);
596  | } echo_off() */
597  | 
598  | /* XXX Doh! These only change the server's terminal.  We need some
599  |    tricky escape sequence to send over the socket.
600  | static void echo_on(int sock) {
601  |   struct termio state;
602  | 
603  |   ioctl(0, TIOCGETP, &state);
604  |   state.c_lflag |= ECHO;
605  |   ioctl(0, TIOCSETP, &state);
606  | } echo_on() */
607  | 
608  | static char *authenticate_user(sk_conn_st *condat) {
609  |   char *user = NULL;
610  |   const char Salt[2] = "DB";
611  |   char input[MAX_INPUT_SIZE];
612  |   int read_result;
613  |   char *password=NULL;
614  |   char *user_password=NULL;
615  |   char user_buf[10];
616  | 
617  |   SK_cd_puts(condat, LOGIN_PROMPT);
618  |   read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE);
619  | 
620  |   strncpy(user_buf, input, 10);
621  | 
622  |   SK_cd_puts(condat, PASSWD_PROMPT);
623  |   /* XXX These aren't working.
624  |   SK_puts(sock, ECHO_ON);
625  |   echo_off(sock);
626  |   */
627  |   read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE);
628  |   /* XXX These aren't working.
629  |   echo_on(sock);
630  |   SK_puts(sock, ECHO_OFF);
631  |   */
632  | 
633  |   password = crypt(input, Salt);
634  | 
635  |   user_password = PR_get_property(user_buf, DEFAULT_USER_NAME);
636  | 
637  |   if (user_password != NULL) {
638  |     if (strcmp(password, user_password) == 0) {
639  |       //user = (char *)calloc(1, strlen(user_buf)+1);
640  |       dieif( wr_malloc((void **)&user, strlen(user_buf)+1) != UT_OK);  
641  |       strcpy(user, user_buf);
642  |     }
643  |   }
644  | 
645  |   if (user == NULL) {
646  |     log_config(user_buf, "unsuccesful login attempt");
647  |   }
648  | 
649  |   return user;
650  | 
651  | } /* authenticate_user() */
652  | 
653  | void PC_interact(int sock) {
654  |   char input[MAX_INPUT_SIZE];
655  |   int connected = 1;
656  |   char *user=NULL;
657  |   sk_conn_st condat;
658  | 
659  |   memset( &condat, 0, sizeof(condat));
660  |   condat.sock = sock;
661  |   SK_getpeerip(sock, &(condat.rIP));
662  |   condat.ip = SK_getpeername(sock);
663  |   
664  |   /* Welcome the client */
665  |   SK_cd_puts(&condat, CO_get_welcome());
666  | 
667  |   /* Authenticate the user */
668  |   if (CO_get_authenticate() == 1) {
669  |     user = authenticate_user(&condat);
670  |   }
671  |   else {
672  |     user="nobody";
673  |   }
674  | 
675  |   if (user != NULL) {
676  |     /* Log admin logging on */
677  |     log_config(user, "logged on");
678  |     
679  |     SK_cd_puts(&condat, CO_get_prompt());
680  | 
681  |     while (condat.rtc==0 && connected) {
682  |       /* Read input */
683  |       SK_cd_gets(&condat, input, MAX_INPUT_SIZE);
684  |       connected = process_input(input, &condat);
685  |     }
686  |     
687  |     /* Log admin logging off */
688  |     log_config(user, "logged off");
689  |   }
690  |   
691  |   /* Close the socket */
692  |   SK_close(sock);
693  | 
694  | } /* PC_interact() */
695  |